前端小菜鸟

SpringSecurity 自定义 AccessDeniedHandler 不生效的问题解决

2024/03/11
433
0

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