40. 启动或禁用管理员(续)
关于Controller层
由于Service设计了2个业务方法,分别用于启用和禁用,在控制器层,应该也设计2个方法,分别用于处理启用管理员的请求和禁用管理员的请求,则客户端在提交请求时,不需要提交enable 属性的值!
则在AdminController 中添加处理请求的方法:
@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();
}
@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 {
public PasswordEncoder passwordEncoder() {
log.debug("创建@Bean方法定义的对象:PasswordEncoder");
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
String[] urls = {
"/doc.html",
"/**/*.js",
"/**/*.css",
"/swagger-resources",
"/v2/api-docs"
};
http.csrf().disable();
http.authorizeRequests()
.antMatchers(urls)
.permitAll()
.anyRequest()
.authenticated();
http.formLogin();
}
}
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);
if ("root".equals(s)) {
UserDetails userDetails = User.builder()
.username("root")
.password("123456")
.accountExpired(false)
.accountLocked(false)
.disabled(false)
.authorities("这是一个山寨的权限标识")
.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 接口类型的对象,则默认的用户名和随机的密码都不会再使用(启动项目中也不会再看到随机的临时密码)。
|