当前位置:   article > 正文

springboot3探索日记(3)——Security6配置_springboot3 security6

springboot3 security6

springboot版本:3.2.0

jdk版本:21

security,跟随boot版本。

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-security</artifactId>
  4. </dependency>

Security6相比Security5及之前的版本,在配置上做出了断层式的改变。和之前继承WebSecurityConfigurerAdapter相比,现在种种配置都是以bean的形式呈现的。

  1. @Slf4j
  2. @EnableWebSecurity
  3. @Configuration
  4. @EnableMethodSecurity(securedEnabled = true, jsr250Enabled = true)
  5. public class SecurityConfig {
  6. // 白名单
  7. @Value("#{'${config.security.white-list}'.split(',')}")
  8. private String[] whiteList;
  9. @Resource
  10. private AuthenticationTokenFilter authenticationTokenFilter;
  11. @Bean
  12. public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
  13. return httpSecurity
  14. .authorizeHttpRequests(req -> req.requestMatchers(whiteList).permitAll()
  15. .anyRequest().authenticated())
  16. .exceptionHandling(http -> http.authenticationEntryPoint(failureHandling()))
  17. // token过滤器
  18. .addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
  19. .csrf(AbstractHttpConfigurer::disable)
  20. .cors(AbstractHttpConfigurer::disable)
  21. // 无状态
  22. .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
  23. .build();
  24. }
  25. @Bean
  26. public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
  27. return authenticationConfiguration.getAuthenticationManager();
  28. }
  29. /**
  30. * 强散列哈希加密实现
  31. */
  32. @Bean
  33. public PasswordEncoder bCryptPasswordEncoder() {
  34. return new BCryptPasswordEncoder();
  35. }
  36. /**
  37. * 验证失败处理器
  38. *
  39. */
  40. public AuthenticationEntryPoint failureHandling() {
  41. return (request, response, exception) -> {
  42. log.error(exception.getMessage());
  43. RespEnum resultEnum = RespEnum.UNAUTHORIZED;
  44. exception.printStackTrace();
  45. Resp<Void> resp = Resp.error(resultEnum);
  46. response.setContentType("application/json");
  47. response.setCharacterEncoding("utf-8");
  48. response.getWriter().write(JSON.toJSONString(resp));
  49. };
  50. }
  51. }

这里用过滤器的方式验证用户,用户信息放到请求上下文中

  1. @Component
  2. public class AuthenticationTokenFilter extends OncePerRequestFilter {
  3. @Resource
  4. private TokenService tokenService;
  5. @Override
  6. public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
  7. String token = SecurityUtils.getToken(request);
  8. // 无token不加载用户信息
  9. if (Func.isEmpty(token) || token.startsWith("Basic")) {
  10. chain.doFilter(request, response);
  11. return;
  12. }
  13. // 解析token,并从redis中取出loginUser
  14. LoginUser loginUser = tokenService.verifyToken(token);
  15. // security的认证实际上最终操作的就是这个authenticationToken
  16. UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
  17. authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
  18. SecurityContextHolder.getContext().setAuthentication(authenticationToken);
  19. chain.doFilter(request, response);
  20. }
  21. }

tokenService不变(主要是对token、用户的处理)。

  1. @Component
  2. public class TokenService {
  3. @Resource
  4. private RedisTemplate<String, String> redisTemplate;
  5. // 令牌默认存储时长
  6. protected static final long EXPIRE_SECOND = 3600;
  7. // token在redis中的key
  8. private final static String ACCESS_TOKEN = "login_tokens:";
  9. /**
  10. * 创建令牌
  11. */
  12. public String createToken(LoginUser loginUser) {
  13. String token = IdUtil.nanoId();
  14. // 存储
  15. refreshToken(loginUser, token);
  16. return token;
  17. }
  18. /**
  19. * 获取用户身份信息
  20. *
  21. * @return 用户信息
  22. */
  23. public LoginUser getLoginUser(String token) {
  24. if (StringUtils.isNotEmpty(token)) {
  25. String tokenKey = getTokenKey(token);
  26. String userStr = redisTemplate.opsForValue().get(tokenKey);
  27. LoginUser loginUser = JSON.parseObject(userStr, LoginUser.class);
  28. return loginUser;
  29. }
  30. return null;
  31. }
  32. /**
  33. * 删除用户缓存信息
  34. */
  35. public void removeToken(String token) {
  36. if (token == null) {
  37. return;
  38. }
  39. String tokenKey = getTokenKey(token);
  40. redisTemplate.delete(tokenKey);
  41. }
  42. /**
  43. * 验证令牌有效期,相差不足120分钟,自动刷新缓存
  44. *
  45. * @param token
  46. */
  47. public LoginUser verifyToken(String token) {
  48. LoginUser loginUser = getLoginUser(token);
  49. // 刷新token
  50. refreshToken(loginUser, token);
  51. return loginUser;
  52. }
  53. /**
  54. * 刷新令牌有效期
  55. *
  56. * @param loginUser 登录信息
  57. */
  58. public void refreshToken(LoginUser loginUser, String token) {
  59. // 将loginUser缓存
  60. String userKey = getTokenKey(token);
  61. ValueOperations<String, String> forValue = redisTemplate.opsForValue();
  62. forValue.set(userKey, JSON.toJSONString(loginUser) , Duration.ofSeconds(EXPIRE_SECOND));
  63. }
  64. private String getTokenKey(String token) {
  65. return ACCESS_TOKEN + token;
  66. }
  67. }

登录不变,还是原先的,核心代码:

  1. @Resource
  2. private AuthenticationManager authenticationManager;
  3. public Resp<String> login(@Valid @RequestBody LoginReqDTO loginBody) {
  4. String username = loginBody.getUsername();
  5. String password = loginBody.getPassword();
  6. UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
  7. Authentication authenticate = authenticationManager.authenticate(authenticationToken);
  8. LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
  9. String token = tokenService.createToken(loginUser);
  10. return Resp.success(token);
  11. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/484592
推荐阅读
相关标签
  

闽ICP备14008679号