在Spring Security中区分401(未经授权)/ 403(禁止)在Global ExceptionException中的拒绝异常

mcdcgff0  于 2024-01-05  发布在  Spring
关注(0)|答案(1)|浏览(155)

我在Sping Boot 应用程序中实现了Spring Security,默认情况下,它会正确地抛出401(未经授权)或403(禁止),这样下面的单元测试就可以工作了:

  1. @Test
  2. void notLoggedIn() throws Exception {
  3. mockMvc.perform(get("/service")) //
  4. .andExpect(status().isUnauthorized()); // 401 is returned and caught
  5. }
  6. void loggedInWithIncorrectRole() throws Exception {
  7. mockMvc.perform(get("/service").with(user("someuser").roles("invalidRole"))) //
  8. .andExpect(status().isForbidden()); // 403 is returned and caught
  9. }

字符串
然后我添加了一个@ControllerAdvice全局ExceptionHandler来捕获应用程序抛出的所有异常。现在,所有的安全异常都以org.springframework.security.access.AccessDeniedException: Access Denied的形式出现在ExceptionHandler中。在这个异常中,401和403都被合并了。

  1. @ControllerAdvice
  2. public class AppExceptionHandler {
  3. @ExceptionHandler(Exception.class)
  4. public ResponseEntity<ErrorResponse> handleException(Exception e, WebRequest request) {
  5. log.error(e);
  6. if ("org.springframework.security.access.AccessDeniedException".equals(e.getClass().getName())) {
  7. // This will catch BOTH 401 and 403, no distinction
  8. return new ResponseEntity<ErrorResponse>(HttpStatus.UNAUTHORIZED);
  9. } else {
  10. return ResponseEntity.internalServerError()
  11. .body(new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, "Error occurred));
  12. }
  13. }


堆栈跟踪总是

  1. org.springframework.security.access.AccessDeniedException: Access Denied
  2. at org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor.attemptAuthorization(AuthorizationManagerBeforeMethodInterceptor.java:256)
  3. at org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor.invoke(AuthorizationManagerBeforeMethodInterceptor.java:197)
  4. at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
  5. at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:765)
  6. at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:717)


如何区分?

7gcisfzg

7gcisfzg1#

@ControllerAdvice无法处理BadCredentialsException,当没有找到用户或不正确的凭据时会抛出BadCredentialsException,因为尚未调用控制器方法。
在这种情况下,BasicAuthenticationEntryPoint会被触发。如果你想记录所有失败的尝试,你可以创建一个自定义入口点,如下所示:

  1. public class BasicSecurityEntryPoint implements AuthenticationEntryPoint {
  2. @Override
  3. public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
  4. // TODO: Add your logic here to log the failed attempts
  5. }
  6. }

字符串
确保正确配置:

  1. @Bean
  2. public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
  3. httpSecurity
  4. .httpBasic(c -> c.authenticationEntryPoint(new BasicSecurityEntryPoint()));
  5. return httpSecurity.build();
  6. }

展开查看全部

相关问题