Filters:
ExceptionTranslationFilter:有两种异常抛出!
private void handleException(HttpServletRequest request, HttpServletResponse response, FilterChain chain, RuntimeException exception) throws IOException, ServletException { if (exception instanceof AuthenticationException) {//如果是AuthenticationException的类型,直接发送到 sendStartAuthentication if (logger.isDebugEnabled()) { logger.debug("Authentication exception occurred; redirecting to authentication entry point", exception); } sendStartAuthentication(request, response, chain, (AuthenticationException) exception); } else if (exception instanceof AccessDeniedException) { if (authenticationTrustResolver.isAnonymous(SecurityContextHolder.getContext().getAuthentication())) { if (logger.isDebugEnabled()) { logger.debug("Access is denied (user is anonymous); redirecting to authentication entry point", exception); } sendStartAuthentication(request, response, chain, new InsufficientAuthenticationException( "Full authentication is required to access this resource")); } else { if (logger.isDebugEnabled()) { logger.debug("Access is denied (user is not anonymous); delegating to AccessDeniedHandler", exception); } accessDeniedHandler.handle(request, response, (AccessDeniedException) exception); } } }
第一种:就是普通的授权异常了!AuthenticationException
1. 如果没有授权的访问,抛出 AuthenticationException的子类,判断它的类型为AuthenticationException之后,调用sendStartAuthentication方法去判断
protected void sendStartAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, AuthenticationException reason) throws ServletException, IOException { // SEC-112: Clear the SecurityContextHolder's Authentication, as the // existing Authentication is no longer considered valid SecurityContextHolder.getContext().setAuthentication(null); requestCache.saveRequest(request, response); logger.debug("Calling Authentication entry point."); authenticationEntryPoint.commence(request, response, reason); }
清空SecurityContextHolder上下文中的Authentication , 然后委托给authenticationEntryPoint去发送分发页面!默认的是
LoginUrlAuthenticationEntryPoint(我们可在applicationContext.xml配置中,设置entry-point-ref="loginUrlAuthenticationEntryPoint",
这里的loginUrlAuthenticationEntryPoint是自定义的实现类)
<bean:bean id="loginUrlAuthenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint" p:loginFormUrl="/login/welcome"> <!-- 这里默认是DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL? --> /spring_security_login是默认发送到的登录界面 --> </bean:bean>
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; String redirectUrl = null; if (useForward) {//是否选择 Forward模式,如果不是,发送302重定向,跳转到 登录页面。默认为false. if (forceHttps && "http".equals(request.getScheme())) { redirectUrl = buildHttpsRedirectUrlForRequest(httpRequest); } if (redirectUrl == null) { String loginForm = determineUrlToUseForThisRequest(httpRequest, httpResponse, authException);//提供给子类覆盖!,是否临时修改登录界面的URL. if (logger.isDebugEnabled()) { logger.debug("Server side forward to: " + loginForm); } RequestDispatcher dispatcher = httpRequest.getRequestDispatcher(loginForm); dispatcher.forward(request, response); return; } } else { // redirect to login page. Use https if forceHttps true redirectUrl = buildRedirectUrlToLoginPage(httpRequest, httpResponse, authException);//创建重定向URL } httpResponse.sendRedirect(httpResponse.encodeRedirectURL(redirectUrl)); }
第二种:是访问资源被Denied的异常,AccessDeniedException