Spring Security3源码分析(15)-ExceptionTranslationFilter分析

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

ExceptionTranslationFilter过滤器对应的类路径为

org.springframework.security.web.access.ExceptionTranslationFilter

从类名就看出这个过滤器用于异常翻译的。但是从这个过滤器在filterchain中的位置来看,它仅仅处于倒数第三的位置(这个filter后面分为是FilterSecurityInterceptor、SwitchUserFilter),所以ExceptionTranslationFilter只能捕获到后面两个过滤器所抛出的异常。

这里需要强调一下,spring security中的异常类基本上都继承RuntimeException。

接着看ExceptionTranslationFilter执行过程

Java代码

  1. //doFilter拦截到请求时,不做处理。仅仅处理后面filter所抛出的异常
  2. public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
  3. throws IOException, ServletException {
  4. HttpServletRequest request = (HttpServletRequest) req;
  5. HttpServletResponse response = (HttpServletResponse) res;
  6. try {
  7. chain.doFilter(request, response);
  8. }
  9. catch (IOException ex) {
  10. throw ex;
  11. }
  12. catch (Exception ex) {
  13. //这里主要是从异常堆栈中提取SpringSecurityException
  14. Throwable[] causeChain = throwableAnalyzer.determineCauseChain(ex);
  15. RuntimeException ase = (AuthenticationException)
  16. throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class, causeChain);
  17. if (ase == null) {
  18. ase = (AccessDeniedException)throwableAnalyzer.getFirstThrowableOfType(AccessDeniedException.class, causeChain);
  19. }
  20. //如果提取到安全异常,则进行处理
  21. if (ase != null) {
  22. handleException(request, response, chain, ase);
  23. } else {
  24. //没有安全异常,继续抛出
  25. // Rethrow ServletExceptions and RuntimeExceptions as-is
  26. if (ex instanceof ServletException) {
  27. throw (ServletException) ex;
  28. }
  29. else if (ex instanceof RuntimeException) {
  30. throw (RuntimeException) ex;
  31. }
  32. throw new RuntimeException(ex);
  33. }
  34. }
  35. }
  36. //处理安全异常
  37. private void handleException(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
  38. RuntimeException exception) throws IOException, ServletException {
  39. //如果是认证异常,由sendStartAuthentication处理
  40. if (exception instanceof AuthenticationException) {
  41. sendStartAuthentication(request, response, chain, (AuthenticationException) exception);
  42. }
  43. //如果是访问拒绝异常,由访问拒绝处理类的handle处理
  44. else if (exception instanceof AccessDeniedException) {
  45. if (authenticationTrustResolver.isAnonymous(SecurityContextHolder.getContext().getAuthentication())) {
  46. sendStartAuthentication(request, response, chain, new InsufficientAuthenticationException(
  47. “Full authentication is required to access this resource”));
  48. }
  49. else {
  50. accessDeniedHandler.handle(request, response, (AccessDeniedException) exception);
  51. }
  52. }
  53. }

先分析如何处理认证异常

Java代码

  1. //处理认证异常
  2. protected void sendStartAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
  3. AuthenticationException reason) throws ServletException, IOException {
  4. // SEC-112: Clear the SecurityContextHolder’s Authentication, as the
  5. // existing Authentication is no longer considered valid
  6. //首先把SecurityContext中的认证实体置空
  7. SecurityContextHolder.getContext().setAuthentication(null);
  8. //通过cache保存当前的请求信息(分析RequestCacheAwareFilter时再深入)
  9. requestCache.saveRequest(request, response);
  10. logger.debug(“Calling Authentication entry point.”);
  11. //由认证入口点开始处理
  12. authenticationEntryPoint.commence(request, response, reason);
  13. }

这里补充一下

authenticationEntryPoint是由配置http标签时,通过什么认证入口来决定注入相应的入口点bean的。请看下面的对应关系列表
form-login认证:LoginUrlAuthenticationEntryPoint
http-basic认证:BasicAuthenticationEntryPoint
openid-login认证:LoginUrlAuthenticationEntryPoint
x509认证:Http403ForbiddenEntryPoint

就不一一分析每个EntryPoint了,着重看一下LoginUrlAuthenticationEntryPoint

Java代码

  1. //主要目的是完成跳转任务
  2. //创建该bean时,只注入了loginFormUrl属性,其他类变量均为默认值
  3. public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
  4. throws IOException, ServletException {
  5. HttpServletRequest httpRequest = (HttpServletRequest) request;
  6. HttpServletResponse httpResponse = (HttpServletResponse) response;
  7. String redirectUrl = null;
  8. //默认为false
  9. if (useForward) {
  10. if (forceHttps && “http”.equals(request.getScheme())) {
  11. redirectUrl = buildHttpsRedirectUrlForRequest(httpRequest);
  12. }
  13. if (redirectUrl == null) {
  14. String loginForm = determineUrlToUseForThisRequest(httpRequest, httpResponse, authException);
  15. RequestDispatcher dispatcher = httpRequest.getRequestDispatcher(loginForm);
  16. dispatcher.forward(request, response);
  17. return;
  18. }
  19. } else {
  20. //返回的url为loginFormUrl配置的值,如果未配置,跳转到默认登录页面/spring_security_login
  21. redirectUrl = buildRedirectUrlToLoginPage(httpRequest, httpResponse, authException);
  22. }
  23. redirectStrategy.sendRedirect(httpRequest, httpResponse, redirectUrl);
  24. }

接着分析访问拒绝类异常的处理过程,看AccessDeniedHandlerImpl的handle方法

Java代码

  1. public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException)
  2. throws IOException, ServletException {
  3. if (!response.isCommitted()) {
  4. //如果配置了access-denied-page属性,跳转到指定的url
  5. if (errorPage != null) {
  6. // Put exception into request scope (perhaps of use to a view)
  7. request.setAttribute(SPRING_SECURITY_ACCESS_DENIED_EXCEPTION_KEY, accessDeniedException);
  8. // Set the 403 status code.
  9. response.setStatus(HttpServletResponse.SC_FORBIDDEN);
  10. // forward to error page.
  11. RequestDispatcher dispatcher = request.getRequestDispatcher(errorPage);
  12. dispatcher.forward(request, response);
  13. //如果没有配置,则直接响应403禁止访问的错误信息到浏览器端
  14. } else {
  15. response.sendError(HttpServletResponse.SC_FORBIDDEN, accessDeniedException.getMessage());
  16. }
  17. }
  18. }

通过以上分析,可以大体上认识到ExceptionTranslationFilter主要拦截两类安全异常:认证异常、访问拒绝异常。而且仅仅是捕获FilterSecurityInterceptor、SwitchUserFilter以及自定义拦截器的异常。所以在自定义拦截器时,需要注意在链中的顺序。

在上面分析过程中,有requestCache.saveRequest(request, response);的语句,具体requestCache的用途下篇分析。


来源:http://ddrv.cn

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » Spring Security3源码分析(15)-ExceptionTranslationFilter分析

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏