SpringSecurity自定义异常处理
以下为SpringSecurity默认自带的异常处理机制
两个重要的异常类
1. AccessDeniedException
该异常实现了很多子类。子类都是涉及到权限校验问题的。
2. AuthenticationEntryPoint
同样该异常类也实现了很多子类。springSecurity把异常划分的很细。概括来说都是身份校验问题。
自定异常处理类
public class MyAccessDeniedException extends AccessDeniedException {
public MyAccessDeniedException(String msg) {
super(msg);
}
}
public class MyAuthenticationException extends AuthenticationException {
public MyAuthenticationException(String msg) {
super(msg);
}
}
接下来说说springSecurity是怎么分辨异常类型的,主要是ExceptionTranslationFilter这个filter,下面是它的核心代码
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);
this.logger.debug("Chain processed normally");
} catch (IOException var9) {
throw var9;
} catch (Exception var10) {
// 不管是AccessDeniedException还是AuthenticationEntryPoint都在这里被捕获
Throwable[] causeChain = this.throwableAnalyzer.determineCauseChain(var10);
RuntimeException ase = (AuthenticationException)this.throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class, causeChain);
if (ase == null) {
ase = (AccessDeniedException)this.throwableAnalyzer.getFirstThrowableOfType(AccessDeniedException.class, causeChain);
}
if (ase == null) {
if (var10 instanceof ServletException) {
throw (ServletException)var10;
}
if (var10 instanceof RuntimeException) {
throw (RuntimeException)var10;
}
throw new RuntimeException(var10);
}
if (response.isCommitted()) {
throw new ServletException("Unable to handle the Spring Security Exception because the response is already committed.", var10);
}
this.handleSpringSecurityException(request, response, chain, (RuntimeException)ase);
}
}
// 这个方法是用来判别异常的,决定该异常由什么类处理
private void handleSpringSecurityException(HttpServletRequest request, HttpServletResponse response, FilterChain chain, RuntimeException exception) throws IOException, ServletException {
// 如果是身份校验异常
if (exception instanceof AuthenticationException) {
this.logger.debug("Authentication exception occurred; redirecting to authentication entry point", exception);
this.sendStartAuthentication(request, response, chain, (AuthenticationException)exception);
// 如果是权限校验异常
} else if (exception instanceof AccessDeniedException) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (!this.authenticationTrustResolver.isAnonymous(authentication) && !this.authenticationTrustResolver.isRememberMe(authentication)) {
this.logger.debug("Access is denied (user is not anonymous); delegating to AccessDeniedHandler", exception);
this.accessDeniedHandler.handle(request, response, (AccessDeniedException)exception);
} else {
this.logger.debug("Access is denied (user is " + (this.authenticationTrustResolver.isAnonymous(authentication) ? "anonymous" : "not fully authenticated") + "); redirecting to authentication entry point", exception);
this.sendStartAuthentication(request, response, chain, new InsufficientAuthenticationException(this.messages.getMessage("ExceptionTranslationFilter.insufficientAuthentication", "Full authentication is required to access this resource")));
}
}
}
经由判断的异常类型到不同的异常处理类,这里我直接重写了异常处理机制。
主要有两个AuthenticationEntryPoint(处理AuthenticationEntryPoint类型的异常)和AccessDeniedHandler(处理AccessDeniedException类型的异常)
@Component
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.getWriter().println(e.getMessage());
}
}
@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
httpServletResponse.getWriter().println(e.getMessage());
}
}
注入两个自定义异常处理机制在WebSecurityConfiguration中
@Autowired
private MyAuthenticationEntryPoint myAuthenticationEntryPoint;
@Autowired
private MyAccessDeniedHandler myAccessDeniedHandler;
在configure还需加上
http.exceptionHandling().authenticationEntryPoint(myAuthenticationEntryPoint).accessDeniedHandler(myAccessDeniedHandler);
异常一般可以在这里抛出,得自定义AccessDecisionManager。
@Component
public class MyAccessDecisionManager implements AccessDecisionManager {
@Override
public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> collection) {
throw new MyAuthenticationException("身份校验错误");
throw new MyAccessDeniedException("权限校验错误");
}
@Override
public boolean supports(ConfigAttribute configAttribute) {
return true;
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
以上就是自定义异常处理了,一般适用于前后端分离,我们就可以返回json数据给前端了。
版权声明:本文为XlxfyzsFdblj原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。