SpringSecurity 自定义 AccessDeniedHandler 不生效的问题解决
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// 禁用csrf(防止跨站请求伪造攻击)
.csrf(AbstractHttpConfigurer::disable)
// 使用无状态session,即不使用session缓存数据
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
// 设置白名单
.authorizeHttpRequests(auth -> auth.requestMatchers(URL_WHITELIST).permitAll().anyRequest().authenticated())
// 异常处理器
.exceptionHandling(exception -> exception.authenticationEntryPoint(jwtAuthenticationEntryPoint).accessDeniedHandler(jwtAccessDeniedHandler))
// 添加jwt过滤器
.authenticationProvider(authenticationProvider()).addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@Component
public class JwtAccessDeniedHandler implements AccessDeniedHandler {
private final Logger logger = LoggerFactory.getLogger(JwtAccessDeniedHandler.class);
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.setContentType("application/json;charset=UTF-8");
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
Result<String> result = Result.failed("访问权限不足");
String json = JSONUtil.toJsonStr(result);
logger.info(json);
ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(json.getBytes(StandardCharsets.UTF_8));
outputStream.flush();
outputStream.close();
}
}
在 Security配置类中 正确配置了 AccessDeniedHandler,但是异常时没有走AccessDeniedHandler,却走到了GlobalExceptionHandler。
由于GlobalExceptionHandler 全局异常处理器会比 AccessDeniedHandler 先捕获 AccessDeniedException 异常,因此当配置了 GlobalExceptionHandler 后,会发现 AccessDeniedHandler 失效了。
解决方法就是加一个AccessDeniedExceptionHandler继续往外抛
@ExceptionHandler(AccessDeniedException.class)
public void accessDeniedException(AccessDeniedException exception) throws AccessDeniedException {
throw exception;
}
注意是security的AccessDeniedException