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