当前位置: 首页 > news >正文

项目实战(管理员管理(续),Spring Security框架)

40. 启动或禁用管理员(续)

关于Controller层

由于Service设计了2个业务方法,分别用于启用和禁用,在控制器层,应该也设计2个方法,分别用于处理启用管理员的请求和禁用管理员的请求,则客户端在提交请求时,不需要提交enable属性的值!

则在AdminController中添加处理请求的方法:

// http://localhost:9081/admins/9527/enable
@ApiOperation("启用管理员")
@ApiOperationSupport(order = 310)
@ApiImplicitParam(name = "id", value = "管理员id", required = true, dataType = "long")
@PostMapping("/{id:[0-9]+}/enable")
public JsonResult<Void> setEnable(@PathVariable Long id) {
    log.debug("开始处理【启用管理员】的请求,参数:{}", id);
    adminService.setEnable(id);
    return JsonResult.ok();
}

// http://localhost:9081/admins/9527/disable
@ApiOperation("禁用管理员")
@ApiOperationSupport(order = 311)
@ApiImplicitParam(name = "id", value = "管理员id", required = true, dataType = "long")
@PostMapping("/{id:[0-9]+}/disable")
public JsonResult<Void> setDisable(@PathVariable Long id) {
    log.debug("开始处理【禁用管理员】的请求,参数:{}", id);
    adminService.setDisable(id);
    return JsonResult.ok();
}

41. 关于Spring Security框架

Spring Security主要解决了认证与授权的相关问题。

Spring Security的基础依赖项是spring-security-core,在Spring Boot项目中,通常添加spring-boot-starter-security这个依赖项,它包含了spring-security-core,并且,还自动执行了一系列配置!默认的配置效果有:

  • 所有请求都是必须通过认证的
    • 如果未认证,同步请求将自动跳转到 /login,是框架自带的登录页,非跨域的异步请求将响应 403 错误
  • 提供了默认的登录信息,用户名为 user,密码是启动项目是随机生成的,在启动日志中可以看到
    • 当登录成功后,会自动重定向到此前访问的URL
    • 当登录成功后,可以执行所有同步请求,所有异步的POST请求都暂时不可用
    • 可以通过 /logout 退出登录

42. 关于BCrypt算法

当添加了Spring Security相关的依赖项后,此依赖项中将包含BCryptPasswordEncoder工具类,是一个使用BCrypt算法的密码编码器,它实现了PasswordEncoder接口,并重写了接口中的String encode(String rawPassword)方法,用于对密码原文进行编码(加密),及重写了boolean matches(String rawPassword, String encodedPassword)方法,用于验证密码原文与密文是否对应。

BCrypt算法会自动使用随机的盐值进行加密处理,所以,当反复对同一个原文进行加密处理,每次得到的密文都是不同的,但这并不影响验证密码!

BCrypt算法被设计为是一种慢速运算的算法,可以一定程度上避免或缓解密码被暴力破解(使用循环进行穷举的破解)。

43. 关于Spring Security的基本配置

package cn.tedu.csmall.passport.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Slf4j
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    // @Bean
    public PasswordEncoder passwordEncoder() {
        log.debug("创建@Bean方法定义的对象:PasswordEncoder");
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 【配置白名单】
        // 在配置路径时,星号是通配符
        // 1个星号只能匹配任何文件夹或文件的名称,但不能跨多个层级
        // 例如:/*/test.js,可以匹配到 /a/test.js 和 /b/test.js,但不可以匹配到 /a/b/test.js
        // 2个连续的星号可以匹配若干个文件夹的层级
        // 例如:/**/test.js,可以匹配 /a/test.js 和 /b/test.js 和 /a/b/test.js
        String[] urls = {
                "/doc.html",
                "/**/*.js",
                "/**/*.css",
                "/swagger-resources",
                "/v2/api-docs"
        };

        http.csrf().disable(); // 禁用CSRF(防止伪造的跨域攻击)

        http.authorizeRequests() // 对请求执行认证与授权
                .antMatchers(urls) // 匹配某些请求路径
                .permitAll() // (对此前匹配的请求路径)不需要通过认证即允许访问
                .anyRequest() // 除以上配置过的请求路径以外的所有请求路径
                .authenticated(); // 要求是已经通过认证的

        http.formLogin(); // 开启表单验证,即视为未通过认证时,将重定向到登录表单,如果无此配置,则直接响应403
    }

}

44. 关于登录的账号

默认情况下,Spring Security使用user作为用户名,使用随机的UUID作为密码来登录!如果需要自行指定登录账号,需要自定义一个组件类,实现UserDetailsService接口,此接口中定义了UserDetails loadUserByUsername(String username),在处理认证时,当用户(使用者)输入了用户名、密码并提交,Spring Security就会自动使用用户在表单中输入的用户名来调用loadUserByUsername()方法,作为开发者,应该重写此方法,并根据用户名来返回匹配的UserDetails对象,此对象中应该包含用户的相关信息,例如密码等,当Spring Security得到调用loadUserByUsername()返回的UserDetails对象后,会自动处理后续的认证过程,例如验证密码是否匹配等。

例如,在根包下创建security.UserDetailsServiceImpl类:

package cn.tedu.csmall.passport.security;

import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        log.debug("Spring Security调用了loadUserByUsername()方法,参数:{}", s);
        // 暂时使用模拟数据来处理登录认证,假设正确的用户名和密码分别是root和123456
        if ("root".equals(s)) {
            UserDetails userDetails = User.builder()
                    .username("root")
                    .password("123456")
                    .accountExpired(false)
                    .accountLocked(false)
                    .disabled(false)
                    .authorities("这是一个山寨的权限标识") // 权限,注意,此方法的参数不可以为null,在不处理权限之前,可以写一个随意的字符串值
                    .build();
            log.debug("即将向Spring Security返回UserDetails对象:{}", userDetails);
            return userDetails;
        }
        log.debug("此用户名【{}】不存在,即将向Spring Security返回为null的UserDetails值", s);
        return null;
    }

}

另外,Spring Security在执行认证时,需要使用到密码编码器(PasswordEncoder),则在SecurityConfiguration配置类中添加:

@Bean
public PasswordEncoder passwordEncoder() {
    log.debug("创建@Bean方法定义的对象:PasswordEncoder");
    return NoOpPasswordEncoder.getInstance(); // 无操作的密码编码器,即:不会执行加密处理
}

提示:一旦启动项目时,Spring Security从Spring容器中找到了UserDetailsService接口类型的对象,则默认的用户名和随机的密码都不会再使用(启动项目中也不会再看到随机的临时密码)。

相关文章:

  • 什么是合法IP地址?
  • 在C#中编写递归函数时,为了避免无限递归
  • KMP 算法JavaScript代码实现
  • uniapp外部scss文件使用scss语法不生效.
  • 拓扑排序板子
  • 物联网D3——按键控制LED、光敏传感蜂鸣器
  • 普中51单片机学习(8*8LED点阵)
  • 高校宣讲会管理系统|基于Springboot的高校宣讲会管理系统设计与实现(源码+数据库+文档)
  • C 程序结构
  • Spring Boot到底是如何进行自动配置的?
  • uniapp android 原生插件开发-测试流程
  • 【管理咨询宝藏资料28】某信息技术有限公司战略规划报告
  • JS原型概念讲解
  • 【REST系列】详解REST架构风格 —— 带你阅读Web发展史上的一个重要技术文献
  • 用C++写了基于gec6818开发板上LCD操作的一个类--附带注释(详细)
  • 3、spring cloud 五大组件
  • Redis_在Windows上启动多个Redis服务端
  • 项目启动端口被占用 -- Web server failed to start. Port 8082 was already in use.
  • 做运营如何蹭热点?
  • JAVA反序列化学习笔记
  • 小程序-网络数据请求
  • Vue中KeepAlive 原理与源码分析
  • 蛇形矩阵(模拟)
  • SpringMVC---->自我实现底层机制(吃透springMVC)
  • 计算机毕业设计(附源码)python医疗健康查询系统
  • 找个好用的录屏软件,怎么这么难?
  • 【Node.js】模块的加载机制
  • JavaScript大作业 基于HTML+CSS+JavaScript站酷静态页面官网7页
  • 助力汽修企业突破转型瓶颈,S2B2B商城价格管理模块实现采购交易数字化升级
  • Python作业十一:螺旋矩阵与正方形二维列表
  • 【前端】CSS(3) —— CSS的盒模型与弹性布局
  • 2022高频经典前端面试题(vue2+vue3+typescript+nodejs下篇,含答案)