本文将介绍如何在 Spring Security 中自定义认证和授权失败的处理方式,包括:
认证成功处理
认证失败处理
授权失败处理
自定义类实现 AuthenticationSuccessHandler
接口,重写 onAuthenticationSuccess
方法。
定义认证成功处理器:
java
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler { @Override public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException { httpServletResponse.setCharacterEncoding("UTF-8"); httpServletResponse.setContentType("application/json"); Mapmap = new HashMap<>(); map.put("success", true); map.put("message", "认证成功"); String message = new ObjectMapper().writeValueAsString(map); PrintWriter out = httpServletResponse.getWriter(); out.write(message); out.flush(); out.close(); } }
配置处理器:
java
http.formLogin() .successHandler(new MyAuthenticationSuccessHandler()) ...
自定义类实现 AuthenticationFailureHandler
接口,重写 onAuthenticationFailure
方法。
定义认证失败处理器:
java
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler { @Override public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException { httpServletResponse.setCharacterEncoding("UTF-8"); httpServletResponse.setContentType("application/json"); Mapmap = new HashMap<>(); map.put("success", false); map.put("message", "认证失败"); String message = new ObjectMapper().writeValueAsString(map); httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value()); PrintWriter out = httpServletResponse.getWriter(); out.write(message); out.flush(); out.close(); } }
配置处理器:
java
http.formLogin() .failureHandler(new MyAuthenticationFailureHandler()) ...
当用户请求受保护资源时,需要进行认证和授权检查。Spring Security 提供了两种处理器来处理授权失败:
AuthenticationEntryPoint
:处理匿名用户访问无权限资源时的异常
AccessDeniedHandler
:处理认证过的用户访问无权限资源时的异常
定义 AccessDeniedHandler
(处理已认证用户):
java
public class DefaultAccessDeniedHandler implements AccessDeniedHandler { @Override public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException { httpServletResponse.setCharacterEncoding("UTF-8"); httpServletResponse.setContentType("application/json"); Mapmap = new HashMap<>(); map.put("success", false); map.put("message", "无访问权限"); String message = new ObjectMapper().writeValueAsString(map); PrintWriter out = httpServletResponse.getWriter(); out.write(message); out.flush(); out.close(); } }
定义 AuthenticationEntryPoint
(处理匿名用户):
java
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException { httpServletResponse.setCharacterEncoding("UTF-8"); httpServletResponse.setContentType("application/json"); Mapmap = new HashMap<>(); map.put("success", false); map.put("message", "拒绝访问:" + e.getMessage()); String message = new ObjectMapper().writeValueAsString(map); PrintWriter out = httpServletResponse.getWriter(); out.write(message); out.flush(); out.close(); } }
配置异常处理器:
java
http.exceptionHandling() .accessDeniedHandler(new DefaultAccessDeniedHandler()) // 认证成功但权限检查失败的处理器 .authenticationEntryPoint(new MyAuthenticationEntryPoint()); // 匿名用户的权限检查失败的处理器
通过自定义 Spring Security 的异常处理器,我们可以:
统一认证成功/失败的响应格式
提供更友好的授权失败提示
实现前后端分离架构下的统一错误处理
这些自定义处理器可以很好地集成到 RESTful API 服务中,提供标准化的错误响应。