1、ExceptionTranslationFilter
ExceptionTranslationFilter异常转换器位于整个springSecurityFilterChain的后方 ,用来转换整个链路中出现的异常。此过滤器本身不处理异常。而是将认证过程中出现的异常交给 内部维护的一些类去处理,一般处理两大异常:AccessDeniedException授权异常和
AuthenticationException认证异常
public class ExceptionTranslationFilter extends GenericFilterBean {
// 忽略代码....
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
try {
chain.doFilter(request, response);
}
catch (IOException ex) {
throw ex;
}
catch (Exception ex) {
// 尝试从stacktrace中提取SpringSecurityException
Throwable[] causeChain = throwableAnalyzer.determineCauseChain(ex);
RuntimeException ase = (AuthenticationException) throwableAnalyzer
.getFirstThrowableOfType(AuthenticationException.class, causeChain);
if (ase == null) {
ase = (AccessDeniedException) throwableAnalyzer.getFirstThrowableOfType(AccessDeniedException.class, causeChain);
}
if (ase != null) {
if (response.isCommitted()) {
throw new ServletException("", ex);
}
//核心代码
handleSpringSecurityException(request, response, chain, ase);
}
else {
if (ex instanceof ServletException) {throw (ServletException) ex;}
else if (ex instanceof RuntimeException) {throw (RuntimeException) ex;}
throw new RuntimeException(ex);
}
}
}
private void handleSpringSecurityException(HttpServletRequest request,
HttpServletResponse response, FilterChain chain, RuntimeException exception)
throws IOException, ServletException {
//如果是认证异常
if (exception instanceof AuthenticationException) {
sendStartAuthentication(request, response, chain,(AuthenticationException) exception);
}
//如果是授权异常
else if (exception instanceof AccessDeniedException) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authenticationTrustResolver.isAnonymous(authentication) || authenticationTrustResolver.isRememberMe(authentication)) {
sendStartAuthentication(
request,
response,
chain,
new InsufficientAuthenticationException(messages.getMessage("")));
}
else {
accessDeniedHandler.handle(request, response,(AccessDeniedException) exception);
}
}
}
// 忽略代码....
}
2、自定义403异常处理
前面和大家介绍了 Spring Security 中默认的处理逻辑,实际开发中,我们可以需要做一些调整,很简单,在 exceptionHandling 上进行配置即可。
首先自定义授权异常处理类:
@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {
@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);
PrintWriter out = response.getWriter();
out.write(new ObjectMapper().writeValueAsString(JsonResultHelper.JsonResultFail("权限不足,请联系管理员")));
out.flush();
out.close();
}
}
然后在 SecurityConfig 中进行配置,如下:
@Override
protected void configure(HttpSecurity auth) throws Exception {
auth.addFilterAt(myUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
auth.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and().exceptionHandling().accessDeniedHandler(myAccessDeniedHandler)
.and()
.httpBasic();
}