Spring Security配置问题:浏览器访问接口出现Access Denied异常
问题描述
我配置了如下Spring Security的SecurityConfig类:
@Configuration @EnableWebSecurity @RequiredArgsConstructor public class SecurityConfig { private final AuthenticationProvider authenticationProvider; @Bean @Order(1) public SecurityFilterChain securityFilterChain(final HttpSecurity httpSecurity) throws Exception { httpSecurity .csrf(AbstractHttpConfigurer::disable) .authorizeHttpRequests(auth -> auth .requestMatchers("/Auth/**", "/").permitAll() .anyRequest().authenticated() ).sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authenticationProvider(authenticationProvider); return httpSecurity.build(); } }
以及基础的AuthController控制器:
@RestController @RequestMapping("/Auth/") @RequiredArgsConstructor public class AuthController { private final AuthService authService; @PostMapping("RegisterWithUserNameAndPassword") public ResponseEntity<?> registerWithUserNameAndPassword(@RequestBody RegisterRequest authRequest){ try{ return ResponseEntity.ok(authService.register(authRequest)); } catch (Exception e) { return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST); } } @GetMapping("Hello") public ResponseEntity<String> hello(){ return ResponseEntity.ok("Hello Auth controller"); } }
使用Postman访问/Auth/Hello接口时一切正常,可获取正确响应且无报错;但使用浏览器访问该接口时,虽能得到正确的字符串响应,却会抛出如下AccessDeniedException异常:
org.springframework.security.access.AccessDeniedException: Access Denied at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:98) ~[spring-security-web-6.1.2.jar:6.1.2] at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240) ~[spring-security-web-6.1.2.jar:6.1.2] at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227) ~[spring-security-web-6.1.2.jar:6.1.2] at org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137) ~[spring-security-web-6.1.2.jar:6.1.2] at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126) ~[spring-security-web-6.1.2.jar:6.1.2] at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120) ~[spring-security-web-6.1.2.jar:6.1.2]
对应的调试日志如下:
2023-08-13T16:24:50.955+03:00 DEBUG 55724 --- [nio-8090-exec-1] o.s.security.web.FilterChainProxy : Securing GET /Auth/Hello 2023-08-13T16:24:50.962+03:00 DEBUG 55724 --- [nio-8090-exec-1] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext 2023-08-13T16:24:50.969+03:00 DEBUG 55724 --- [nio-8090-exec-1] o.s.security.web.FilterChainProxy : Secured GET /Auth/Hello 2023-08-13T16:24:50.985+03:00 WARN 55724 --- [nio-8090-exec-1] c.m.security.config.JwtAuthFilter : No valid jwt token in Authorization 2023-08-13T16:24:51.002+03:00 DEBUG 55724 --- [nio-8090-exec-2] o.s.security.web.FilterChainProxy : Securing GET /favicon.ico 2023-08-13T16:24:51.002+03:00 DEBUG 55724 --- [nio-8090-exec-2] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext 2023-08-13T16:24:51.005+03:00 DEBUG 55724 --- [nio-8090-exec-2] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access 2023-08-13T16:24:51.008+03:00 DEBUG 55724 --- [nio-8090-exec-2] o.s.security.web.FilterChainProxy : Securing GET /error 2023-08-13T16:24:51.010+03:00 DEBUG 55724 --- [nio-8090-exec-2] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext 2023-08-13T16:24:51.010+03:00 DEBUG 55724 --- [nio-8090-exec-2] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
移除JwtAuthFilter后的调试日志:
2023-08-13T23:19:30.050+03:00 DEBUG 94616 --- [nio-8090-exec-1] o.s.security.web.FilterChainProxy : Securing GET /Auth/Hello 2023-08-13T23:19:30.057+03:00 DEBUG 94616 --- [nio-8090-exec-1] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext 2023-08-13T23:19:30.064+03:00 DEBUG 94616 --- [nio-8090-exec-1] o.s.security.web.FilterChainProxy : Secured GET /Auth/Hello 2023-08-13T23:19:30.097+03:00 DEBUG 94616 --- [nio-8090-exec-2] o.s.security.web.FilterChainProxy : Securing GET /favicon.ico 2023-08-13T23:19:30.097+03:00 DEBUG 94616 --- [nio-8090-exec-2] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext 2023-08-13T23:19:30.101+03:00 DEBUG 94616 --- [nio-8090-exec-2] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access 2023-08-13T23:19:30.103+03:00 DEBUG 94616 --- [nio-8090-exec-2] o.s.security.web.FilterChainProxy : Securing GET /error 2023-08-13T23:19:30.105+03:00 DEBUG 94616 --- [nio-8090-exec-2] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext 2023-08-13T23:19:30.106+03:00 DEBUG 94616 --- [nio-8090-exec-2] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
请问有什么方法可以修复这个异常?
解决方案
原因分析
从调试日志可以明确:异常并非来自/Auth/Hello的请求,而是浏览器自动发起的/favicon.ico请求——该路径不在permitAll列表中,被Spring Security拦截后触发AccessDeniedException。同时Spring Boot默认错误页面路径/error也未被允许访问,导致二次触发异常。
修复方法
方法1:将favicon和error路径加入permitAll
修改SecurityConfig中的授权规则,把/favicon.ico和/error添加到允许匿名访问的范围:
.authorizeHttpRequests(auth -> auth .requestMatchers("/Auth/**", "/", "/favicon.ico", "/error").permitAll() .anyRequest().authenticated() )
方法2:直接忽略favicon路径
如果不需要处理网站图标,可以让Spring Security直接跳过对该路径的拦截,在securityFilterChain方法中添加:
httpSecurity .csrf(AbstractHttpConfigurer::disable) .authorizeHttpRequests(auth -> auth .requestMatchers("/Auth/**", "/").permitAll() .anyRequest().authenticated() ) .sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authenticationProvider(authenticationProvider) .ignoringRequestMatchers("/favicon.ico"); // 忽略favicon请求
方法3:自定义错误页面处理(可选)
若希望更优雅地处理错误,可配置自定义错误控制器,并确保错误路径被允许访问:
@RestController @RequestMapping("/error") public class CustomErrorController { @GetMapping public ResponseEntity<String> handleError() { return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Resource not found"); } }
同时在SecurityConfig的permitAll列表中保留/error路径。
内容的提问来源于stack exchange,提问作者Itamarled
相关产品推荐
相关产品推荐

