异常处理

Spring Security 中的异常主要分为两大类:

  • AuthenticationException:认证异常

  • AccessDeniedException:授权异常

其中认证所涉及到的异常类型比较多,默认提供的异常类型如下:

Drawing
认证异常

相比于认证异常,权限异常类要少很多,默认提供的权限异常如下:

Drawing
授权异常
httpSecurity.exceptionHandling(httpSecurityExceptionHandlingConfigurer -> {
    // 认证异常处理
    httpSecurityExceptionHandlingConfigurer.authenticationEntryPoint((httpServletRequest, httpServletResponse, e) -> {
        if (e instanceof LockedException) {
            httpServletResponse.setCharacterEncoding("UTF-8");
            httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
            httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
            httpServletResponse.getWriter().write("账号被锁定");
            return;
        }
        httpServletResponse.setCharacterEncoding("UTF-8");
        httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
        httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
        httpServletResponse.getWriter().write("请登录");
    });
    // 权限异常处理
    httpSecurityExceptionHandlingConfigurer.accessDeniedHandler((httpServletRequest, httpServletResponse, e) -> {
        httpServletResponse.setCharacterEncoding("UTF-8");
        httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
        httpServletResponse.setStatus(HttpStatus.FORBIDDEN.value());
        httpServletResponse.getWriter().write("权限不足");
    });
    // 设置当前用户请求未授权时跳转的页面
    httpSecurityExceptionHandlingConfigurer.accessDeniedPage("/app/login");
    // 为指定的请求配置默认的AccessDeniedHandler
    httpSecurityExceptionHandlingConfigurer.defaultAccessDeniedHandlerFor((httpServletRequest, httpServletResponse, e) -> {
        httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
        httpServletResponse.setStatus(HttpStatus.FORBIDDEN.value());
        httpServletResponse.getWriter().write("权限不足");
    }, httpServletRequest -> httpServletRequest.getRequestURI().startsWith("/app"));
    // 为指定的请求配置默认的AuthenticationEntryPoint
    httpSecurityExceptionHandlingConfigurer.defaultAuthenticationEntryPointFor((httpServletRequest, httpServletResponse, e) -> {
        httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
        httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
        httpServletResponse.getWriter().write("请登录");
    }, httpServletRequest -> httpServletRequest.getRequestURI().startsWith("/app"));
});

传统web开发

在传统web开发中,当出现认证失败的异常时,我们只需要将其重定向到登录页即可。

@Configuration
@EnableWebSecurity
public class SpringSecurityConfigure {
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        // some code ...
        httpSecurity.exceptionHandling(httpSecurityExceptionHandlingConfigurer -> {
            httpSecurityExceptionHandlingConfigurer.authenticationEntryPoint((httpServletRequest, httpServletResponse, e)->{
                httpServletResponse.sendRedirect("/app/login");
            });
        });
        
        return httpSecurity.build();
    }
}

前后端分离

@Configuration
@EnableWebSecurity
public class SpringSecurityConfigure {
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        // some code ...
        httpSecurity.exceptionHandling(httpSecurityExceptionHandlingConfigurer -> {
            ObjectMapper objectMapper = new ObjectMapper();
            httpSecurityExceptionHandlingConfigurer.authenticationEntryPoint((httpServletRequest, httpServletResponse, e) -> {
                httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                Map<String, String> map = Map.of("message", "认证失败");
                httpServletResponse.getWriter().println(objectMapper.writeValueAsString(map));
            });
        });

        return httpSecurity.build();
    }
}

最后更新于

这有帮助吗?