Spring Security中配置AccessDeniedHandler沒有生效


現象

在 WebSecurityConfigurerAdapter 配置了如下代碼:

// 自定義未授權和未登錄異常
http.exceptionHandling()
        .accessDeniedHandler(new RestAccessDeniedHandler())
        .authenticationEntryPoint(new RestAuthenticationEntryPoint());

在 Controller 層 REST 接口中添加有 @PreAuthorize 注解:

@PreAuthorize(value = "hasAuthority('Users.Update')")
@GetMapping("/hello")
public ResponseEntity<?> hello(@RequestParam(value = "name", required = false, defaultValue = "Tom") String name) {
    return ResponseEntity.ok(RestResponse.buildResponse("Hi: " + name));
}

訪問接口 /hello,報服務端 500 錯誤,沒有執行我們設置的 accessDeniedHandler 來處理權限不足的異常。

原因

當全局異常處理和 @PreAuthorize 注解結合使用時,拋出 AccessDeniedException 異常,不會被 accessDeniedHandler 捕獲,而是會被全局異常捕獲。全局異常處理 AccessDeniedException 的相關示例代碼:

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public ResponseEntity<RestResponse<Object>> handleException(Exception exception) {
        String message = exception.getLocalizedMessage();
        log.error("全局異常捕獲Exception:{}", message, exception);
        HttpStatus httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
        if (exception instanceof BadCredentialsException) {
            httpStatus = HttpStatus.UNAUTHORIZED;
        }
        if (exception instanceof HttpRequestMethodNotSupportedException) {
            httpStatus = HttpStatus.METHOD_NOT_ALLOWED;
        }
        return RestResponse.buildError(httpStatus, message);
    }

    @ExceptionHandler(CommonException.class)
    public ResponseEntity<RestResponse<Object>> handleException(CommonException exception) {
        String message = exception.getLocalizedMessage();
        log.error("全局異常捕獲CommonException:{}", message);
        return RestResponse.buildError(exception.getBusinessStatus(), message);
    }

    @ExceptionHandler(AccessDeniedException.class)
    public ResponseEntity<RestResponse<Object>> handleException(AccessDeniedException exception) {
        String message = exception.getLocalizedMessage();
        log.error("全局異常捕獲AccessDeniedException:{}", message);
        return RestResponse.buildError(HttpStatus.FORBIDDEN, Forbidden);
    }

}

如果需要被 accessDeniedHandler 捕獲處理,則需要這么寫 WebSecurityConfigurerAdapter 的代碼:

http.cors().and()
        .authorizeRequests().antMatchers("/hello0").permitAll()
        // 注意hasRole、hasAuthority 如果出現異常,會調用設置的 accessDeniedHandler 方法
        .antMatchers("/hello").hasAuthority("Users.Update")
        .anyRequest().authenticated();
        
// 自定義未授權和未登錄異常
http.exceptionHandling()
        .accessDeniedHandler(new RestAccessDeniedHandler())
        .authenticationEntryPoint(new RestAuthenticationEntryPoint());

參考資料:

  1. https://github.com/spring-projects/spring-security/issues/6908


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM