当前位置:   article > 正文

SpringBoot3配置SpringSecurity6_spring boot 3.0 security

spring boot 3.0 security

访问1:localhost:8080/security,返回:需要先认证才能访问(说明没有权限)

访问2:localhost:8080/anonymous,返回:anonymous(说明正常访问)


 

相关文件如下:

pom.xml:

  1. <parent>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-parent</artifactId>
  4. <version>3.2.4</version>
  5. <relativePath/> <!-- lookup parent from repository -->
  6. </parent>
  7. <dependency>
  8. <groupId>org.springframework.boot</groupId>
  9. <artifactId>spring-boot-starter-security</artifactId>
  10. </dependency>
  11. <dependency>
  12. <groupId>cn.hutool</groupId>
  13. <artifactId>hutool-all</artifactId>
  14. <version>5.8.18</version>
  15. </dependency>

 WebSecurityConfiguration:

  1. /**
  2. * Spring Security 配置项
  3. */
  4. @Configuration
  5. @EnableWebSecurity
  6. @EnableMethodSecurity
  7. @EnableGlobalAuthentication
  8. public class WebSecurityConfiguration {
  9. @Autowired
  10. private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
  11. @Autowired
  12. private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
  13. @Autowired
  14. private RestAccessDeniedHandler restAccessDeniedHandler;
  15. private UserDetailsService userDetailsService;
  16. @Autowired
  17. private ApplicationContext applicationContext;
  18. @Bean
  19. public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
  20. // 搜寻 匿名标记 url: PreAuthorize("hasAnyRole('anonymous')") 和 PreAuthorize("@tsp.check('anonymous')") 和 AnonymousAccess
  21. Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = applicationContext.getBean(RequestMappingHandlerMapping.class).getHandlerMethods();
  22. Set<String> anonymousUrls = new HashSet<>();
  23. for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethodMap.entrySet()) {
  24. HandlerMethod handlerMethod = infoEntry.getValue();
  25. AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class);
  26. PreAuthorize preAuthorize = handlerMethod.getMethodAnnotation(PreAuthorize.class);
  27. PathPatternsRequestCondition pathPatternsCondition = infoEntry.getKey().getPathPatternsCondition();
  28. Set<String> patternList = new HashSet<>();
  29. if (null != pathPatternsCondition){
  30. Set<PathPattern> patterns = pathPatternsCondition.getPatterns();
  31. for (PathPattern pattern : patterns) {
  32. patternList.add(pattern.getPatternString());
  33. }
  34. }
  35. if (null != preAuthorize && preAuthorize.value().toLowerCase().contains("anonymous")) {
  36. anonymousUrls.addAll(patternList);
  37. } else if (null != anonymousAccess && null == preAuthorize) {
  38. anonymousUrls.addAll(patternList);
  39. }
  40. }
  41. httpSecurity
  42. // 禁用basic明文验证
  43. .httpBasic(it -> it.disable())
  44. // 前后端分离架构不需要csrf保护
  45. .csrf(it -> it.disable())
  46. // 禁用默认登录页
  47. .formLogin(it -> it.disable())
  48. // 禁用默认登出页
  49. .logout(it -> it.disable())
  50. // 设置异常的EntryPoint,如果不设置,默认使用Http403ForbiddenEntryPoint
  51. .exceptionHandling(exceptions -> {
  52. // 401
  53. exceptions.authenticationEntryPoint(restAuthenticationEntryPoint);
  54. // 403
  55. exceptions.accessDeniedHandler(restAccessDeniedHandler);
  56. })
  57. // 前后端分离是无状态的,不需要session了,直接禁用。
  58. .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
  59. .authorizeHttpRequests(authorizeHttpRequests -> authorizeHttpRequests
  60. // 允许匿名访问
  61. .requestMatchers(anonymousUrls.toArray(new String[0])).permitAll()
  62. // 允许所有OPTIONS请求
  63. .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
  64. // 允许 SpringMVC 的默认错误地址匿名访问
  65. .requestMatchers("/error").permitAll()
  66. // 允许任意请求被已登录用户访问,不检查Authority
  67. .anyRequest().authenticated())
  68. .authenticationProvider(authenticationProvider())
  69. // 加我们自定义的过滤器,替代UsernamePasswordAuthenticationFilter
  70. .addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
  71. return httpSecurity.build();
  72. }
  73. @Bean
  74. public CorsFilter corsFilter() {
  75. UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
  76. CorsConfiguration config = new CorsConfiguration();
  77. // 允许所有域名进行跨域调用
  78. config.addAllowedOrigin("*");
  79. // 放行全部原始头信息
  80. config.addAllowedHeader("*");
  81. // 允许所有请求方法跨域调用
  82. config.addAllowedMethod("OPTIONS");
  83. config.addAllowedMethod("GET");
  84. config.addAllowedMethod("POST");
  85. config.addAllowedMethod("PUT");
  86. config.addAllowedMethod("DELETE");
  87. source.registerCorsConfiguration("/**", config);
  88. return new CorsFilter(source);
  89. }
  90. @Bean
  91. public UserDetailsService userDetailsService() {
  92. return username -> userDetailsService.loadUserByUsername(username);
  93. }
  94. @Bean
  95. public PasswordEncoder passwordEncoder() {
  96. return new BCryptPasswordEncoder();
  97. }
  98. @Bean
  99. public AuthenticationProvider authenticationProvider() {
  100. DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
  101. authProvider.setUserDetailsService(userDetailsService());
  102. // 设置密码编辑器
  103. authProvider.setPasswordEncoder(passwordEncoder());
  104. return authProvider;
  105. }
  106. }

JwtAuthenticationTokenFilter
  1. /**
  2. * JWT登录授权过滤器
  3. */
  4. @Component
  5. public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
  6. @Override
  7. protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response,
  8. @NonNull FilterChain chain) throws ServletException, IOException {
  9. String authorization = request.getHeader("Authorization");
  10. response.setCharacterEncoding("utf-8");
  11. if (null == authorization){
  12. // 没有token
  13. chain.doFilter(request, response);
  14. return;
  15. }
  16. try{
  17. if (!authorization.startsWith("Bearer ")){
  18. // token格式不正确
  19. response.sendError(HttpServletResponse.SC_BAD_REQUEST, "token格式不正确");
  20. return;
  21. }
  22. boolean verify = MyJWTUtil.verify(authorization);
  23. if(!verify){
  24. // token格式不正确
  25. response.sendError(HttpServletResponse.SC_BAD_REQUEST, "token验证失败");
  26. return;
  27. }
  28. }catch (Exception e){
  29. // token格式不正确
  30. response.sendError(HttpServletResponse.SC_BAD_REQUEST, "token验证失败");
  31. return;
  32. }
  33. JWT jwt = MyJWTUtil.parseToken(authorization);
  34. Object uid = jwt.getPayload("uid");
  35. // todo 解析JWT获取用户信息
  36. LoginUser loginUser = new LoginUser();
  37. UsernamePasswordAuthenticationToken authenticationToken =
  38. new UsernamePasswordAuthenticationToken(loginUser,null,null);
  39. SecurityContextHolder.getContext().setAuthentication(authenticationToken);
  40. chain.doFilter(request, response);
  41. }
  42. }
RestAuthenticationEntryPoint:
  1. /**
  2. * 认证失败处理类
  3. */
  4. @Component
  5. public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
  6. @Override
  7. public void commence(HttpServletRequest request, HttpServletResponse response,
  8. AuthenticationException authException) throws IOException {
  9. response.setHeader("Access-Control-Allow-Origin", "*");
  10. response.setHeader("Cache-Control", "no-cache");
  11. response.setContentType("application/json");
  12. response.setCharacterEncoding("UTF-8");
  13. response.setStatus(HttpStatus.UNAUTHORIZED.value());
  14. response.getWriter().println(authException == null? "Unauthorized" : "需要先认证才能访问");
  15. response.getWriter().flush();
  16. }
  17. }
RestAccessDeniedHandler:
  1. /**
  2. * 自定义无权访问处理类
  3. */
  4. @Component
  5. public class RestAccessDeniedHandler implements AccessDeniedHandler {
  6. @Override
  7. public void handle(HttpServletRequest request, HttpServletResponse response,
  8. AccessDeniedException accessDeniedException) throws IOException {
  9. response.setHeader("Access-Control-Allow-Origin", "*");
  10. response.setHeader("Cache-Control", "no-cache");
  11. response.setContentType("application/json");
  12. response.setCharacterEncoding("UTF-8");
  13. response.setStatus(HttpStatus.FORBIDDEN.value());
  14. // response.getWriter()
  15. // .println(accessDeniedException==null?"AccessDenied":accessDeniedException.getMessage());
  16. response.getWriter().println(accessDeniedException == null? "AccessDenied" : "没有访问权限");
  17. response.getWriter().flush();
  18. }
  19. }
AnonymousAccess:
  1. /**
  2. * 用于标记匿名访问方法
  3. */
  4. @Target(ElementType.METHOD)
  5. @Retention(RetentionPolicy.RUNTIME)
  6. public @interface AnonymousAccess {
  7. }
MyJWTUtil:
  1. /**
  2. * JWT工具类
  3. */
  4. public class MyJWTUtil extends JWTUtil {
  5. /**
  6. * 解析JWT Token
  7. *
  8. * @param token token
  9. * @return {@link JWT}
  10. */
  11. public static boolean verify(String token) {
  12. return verify(token, "LOGIN_TOKEN_KEY_20240410".getBytes());
  13. }
  14. /**
  15. * 解析JWT Token
  16. *
  17. * @param token token
  18. * @return {@link JWT}
  19. */
  20. public static boolean verify(String token, byte[] key) {
  21. if(StrUtil.isNotEmpty(token)){
  22. if(token.startsWith("Bearer ")){
  23. token = token.split("Bearer ")[1].trim();
  24. }
  25. }
  26. return JWT.of(token).setKey(key).verify();
  27. }
  28. /**
  29. * 解析JWT Token
  30. *
  31. * @param token token
  32. * @return {@link JWT}
  33. */
  34. public static JWT parseToken(String token) {
  35. if(StrUtil.isNotEmpty(token)){
  36. if(token.startsWith("Bearer ")){
  37. token = token.split("Bearer ")[1].trim();
  38. }
  39. }
  40. return JWT.of(token);
  41. }
  42. public static String getToken(HttpServletRequest request) {
  43. final String requestHeader = request.getHeader("Authorization");
  44. if (requestHeader != null && requestHeader.startsWith("Bearer ")) {
  45. return requestHeader.substring(7);
  46. }
  47. return null;
  48. }
  49. public static String createToken(String userId) {
  50. Map<String, Object> payload = new HashMap<>(4);
  51. payload.put("uid", userId);
  52. payload.put("expire_time", System.currentTimeMillis() + 1000 * 60 * 60 * 8);
  53. return createToken(payload, "LOGIN_TOKEN_KEY_20240410".getBytes());
  54. }
  55. }

DemoController:
  1. @RestController
  2. public class DemoController {
  3. @GetMapping("anonymous")
  4. @AnonymousAccess
  5. public String loadCondition() {
  6. return "anonymous";
  7. }
  8. @GetMapping("security")
  9. public String security() {
  10. return "security";
  11. }
  12. }

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