文章目录
AbstractAuthenticationProcessingFilter
Declared
package org.springframework.security.web.authentication;
public abstract class AbstractAuthenticationProcessingFilter
extends GenericFilterBean
implements ApplicationEventPublisherAware, MessageSourceAware
Class Jdoc
基于浏览器的基于HTTP的身份认证请求的抽象的处理器。
认证过程
过滤器要求您设置authenticationManager属性。由实现类创建的身份认证请求令牌需要AuthenticationManager来处理。
如果请求与setRequiresAuthenticationRequestMatcher(RequestMatcher)匹配,此过滤器将拦截请求并尝试进行身份认证。
身份认证由attemptAuthentication方法执行,该方法必须由子类实现。
认证成功
如果身份验证成功,则生成的Authentication对象将被放入当前线程的SecurityContext中,该线程保证已由之前的过滤器创建。
登陆成功后,调用配置的AuthenticationSuccessHandler,跳转到合适的目标。默认行为在SavedRequestAwareAuthenticationSuccessHandler中实现,它将使用ExceptionTranslationFilter设置的任何DefaultSavedRequest,并将用户重定向到其中包含的URL。否则将重定向到webapp根“/”。您可以通过注入该类的不同配置实例或使用不同的实现来自定义此行为。
更多相关信息,请参阅successfulAuthentication(HttpServletRequest、HttpServletResponse、FilterChain、Authentication)方法。
认证失败
如果身份认证失败,它将委托给配置的AuthenticationFailureHandler,以便将失败信息传递给客户端。默认的实现是SimpleUrlAuthenticationFailureHandler,它向客户端发送401错误代码。它也可以配置一个故障URL作为替代。同样,你可以在这里注入任何你需要的行为。
事件发布
如果身份认证成功,则将通过应用程序上下文发布InteractiveAuthenticationSuccessEvent事件。如果身份认证不成功,则不会发布任何事件,因为通常是通过特定于AuthenticationManager的应用程序事件进行记录。
Session认证
AbstractAuthenticationProcessingFilter中有一个可选的SessionAuthenticationStrategy,在成功调用attemptAuthentication()后将立即调用它。可以通过注入不同的实现以启用预防会话固定攻击之类的功能,或者控制主体可能同时拥有的会话数。
Method doFilter
Declared
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException
Method Jdoc
调用requiresAuthentication方法来确定请求是否用于身份验证,是否应该由此过滤器处理。如果是身份认证请求,将调用attemptAuthentication方法进行身份认证。接下来有三种可能的结果:
- 返回一个Authentication对象。在调用successfulAuthentication(HttpServletRequest、HttpServletResponse、FilterChain、Authentication)方法之后,将调用所配置的SessionAuthenticationStrategy(用于处理任何与SessionAuthenticationStrategy相关的行为,如创建一个新会话以防止会话固定攻击)
- 认证过程中产生AuthenticationException。unsuccessfulAuthentication方法被调用。
- 返回Null,表示身份认证过程不完整。然后该方法将立即返回,假设子类已经完成了继续身份验证过程所需的任何工作(例如重定向)。此假设是指稍后会有一个请求被该方法接收,其中返回的Authentication对象不是null。
Method Code
//过滤器默认执行方法
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
//确定请求是否用于身份验证,是否应该由此过滤器处理?
if (!requiresAuthentication(request, response)) {
chain.doFilter(request, response);
return;
}
if (logger.isDebugEnabled()) {
logger.debug("Request is to process authentication");
}
Authentication authResult;
try {
//进行身份认证
authResult = attemptAuthentication(request, response);
if (authResult == null) {
// return immediately as subclass has indicated that it hasn't completed
// 当子类表示它还没有完成时立即返回
// authentication
return;
}
// session认证
sessionStrategy.onAuthentication(authResult, request, response);
} catch (InternalAuthenticationServiceException failed) {
logger.error( "An internal error occurred while trying to authenticate the user.", failed);
unsuccessfulAuthentication(request, response, failed);
return;
} catch (AuthenticationException failed) {
// Authentication failed
// 认证失败
unsuccessfulAuthentication(request, response, failed);
return;
}
// Authentication success
// 认证成功
if (continueChainBeforeSuccessfulAuthentication) {
chain.doFilter(request, response);
}
successfulAuthentication(request, response, chain, authResult);
}
Method requiresAuthentication
Declared
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response)
Method Jdoc
表明此过滤器是否能处理当前调用的登陆请求。
在与filterProcessesUrl属性匹配之前,它从请求URL的path部分删除所有参数(例如:https://host/myapp/index.html;jsessionid=blah中的jsessionid参数)
对于特殊的需求,比如Tapestry集成,子类可以重写。
Method Code
protected boolean requiresAuthentication(HttpServletRequest request,
HttpServletResponse response) {
return requiresAuthenticationRequestMatcher.matches(request);
}
Method attemptAuthentication
Declared
public abstract Authentication attemptAuthentication(HttpServletRequest request,HttpServletResponse response) throws AuthenticationException, IOException,ServletException;
Method Jdoc
实际执行身份认证。
实现应执行以下操作之一:
- 为认证成功对用户返回一个完整的认证令牌,表示认证成功。
- 返回null,表示身份认证正在进行中。在返回之前,实现应执行完过程中需要的任何额外工作。
- 如果身份验证过程失败,则抛出AuthenticationException。
Method unsuccessfulAuthentication
Declared
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException
Method Jdoc
认证不成功的默认行为。
- 清理SecurityContextHolder。
- 将异常存储在Session会话中(如果它存在或allowSesssionCreation设置为true)
- 通知配置的RememberMeServices登陆失败。
- 将其他行为委托给AuthenticationFailureHandler。
Method Code
protected void unsuccessfulAuthentication(HttpServletRequest request,
HttpServletResponse response, AuthenticationException failed)
throws IOException, ServletException {
//清理SecurityContextHolder。
SecurityContextHolder.clearContext();
if (logger.isDebugEnabled()) {
logger.debug("Authentication request failed: " + failed.toString(), failed);
logger.debug("Updated SecurityContextHolder to contain null Authentication");
logger.debug("Delegating to authentication failure handler " + failureHandler);
}
//通知配置的RememberMeServices登陆失败。
rememberMeServices.loginFail(request, response);
//将其他行为委托给AuthenticationFailureHandler。
failureHandler.onAuthenticationFailure(request, response, failed);
}
Method successfulAuthentication
Declared
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException
Method Jdoc
认证成功的默认行为。
- 在SecurityContextHolder中设置成功的Authentication对象。
- 通知已配置的RememberMeServices–登陆成功
- 通过配置的ApplicationEventPublisher触发InteractiveAuthenticationSuccessEvent事件
- 将其他行为委托给AuthenticationSuccessHandler。
Method Code
protected void successfulAuthentication(HttpServletRequest request,
HttpServletResponse response, FilterChain chain, Authentication authResult)
throws IOException, ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Authentication success. Updating SecurityContextHolder to contain: "
+ authResult);
}
//在SecurityContextHolder中设置成功的Authentication对象。
SecurityContextHolder.getContext().setAuthentication(authResult);
//通知已配置的RememberMeServices--登陆成功
rememberMeServices.loginSuccess(request, response, authResult);
// Fire event
//通过配置的ApplicationEventPublisher触发InteractiveAuthenticationSuccessEvent事件
if (this.eventPublisher != null) {
eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(
authResult, this.getClass()));
}
//将其他行为委托给AuthenticationSuccessHandler。
successHandler.onAuthenticationSuccess(request, response, authResult);
}