无法捕获SpringSecurity的认证和鉴权中发生异常的原因
使用@ControllerAdvice的全局异常处理器无法捕获到SpringSecurity中的异常,原因如下:
在SpringSecurity中,如果认证或者授权的过程中出现了异常会被ExceptionTranslationFilter捕获到。在ExceptionTranslationFilter中会去判断是认证失败还是授权失败出现的异常:
- 如果是【认证】过程中出现的异常会被封装成AuthenticationException然后调用AuthenticationEntryPoint对象的方法去进行异常处理。
- 如果是【授权】过程中出现的异常会被封装成AccessDeniedException然后调用AccessDeniedHandler对象的方法去进行异常处理。
所以如果我们需要自定义异常处理,我们只需要实现AuthenticationEntryPoint和AccessDeniedHandler接口,然后配置给SpringSecurity即可。
代码实现
WebUtils工具类,用来渲染字符串:
public class WebUtils {/*** 将字符串渲染到客户端** @param response 渲染对象* @param string 待渲染的字符串* @return null*/public static String renderString(HttpServletResponse response, String string) {try {response.setStatus(200);response.setContentType("application/json");response.setCharacterEncoding("utf-8");response.getWriter().print(string);} catch (IOException e) {e.printStackTrace();}return null;}
}
AuthenticationEntryPoint 自定义实现类
@Component
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {ResponseResult result = new ResponseResult(401, authException.getMessage());String json = JSON.toJSONString(result);WebUtils.renderString(response, json);}
}
AccessDeniedHandler 自定义实现类:
@Component
public class AccessDeniedHandlerImpl implements AccessDeniedHandler {@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {ResponseResult result = new ResponseResult(403, accessDeniedException.getMessage());String json = JSON.toJSONString(result);WebUtils.renderString(response, json);}
}
将自定义异常处理器配置给SpringSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {//注入@Autowiredprivate AuthenticationEntryPoint authenticationEntryPoint;@Autowiredprivate AccessDeniedHandler accessDeniedHandler;@Overrideprotected void configure(HttpSecurity http) throws Exception {//配置自定义异常处理器http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).accessDeniedHandler(accessDeniedHandler);}
}
测试
授权未通过时: