AnonymousAuthenticationFilter
用于实现匿名登陆。如果SecurityContext没有写入认证信息,该filter会在其中写入一个AnonymousAuthenticationToken
。
它的逻辑比较简单,如下所示:
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
// 如果SecurityContext没有保存认证信息
if (SecurityContextHolder.getContext().getAuthentication() == null) {
// 在SecurityContext设置一个AnonymousAuthenticationToken
SecurityContextHolder.getContext().setAuthentication(createAuthentication((HttpServletRequest) req));
if (this.logger.isTraceEnabled()) {
this.logger.trace(LogMessage.of(() -> "Set SecurityContextHolder to "
+ SecurityContextHolder.getContext().getAuthentication()));
}
else {
this.logger.debug("Set SecurityContextHolder to anonymous SecurityContext");
}
}
else {
if (this.logger.isTraceEnabled()) {
this.logger.trace(LogMessage.of(() -> "Did not set SecurityContextHolder since already authenticated "
+ SecurityContextHolder.getContext().getAuthentication()));
}
}
chain.doFilter(req, res);
}
SessionManagementFilter
如果有新用户认证通过,调用session相关的操作,即SessionAuthenticationStrategy
。例如激活session-fixation保护机制或检测用户多次登录。
有关SessionAuthenticationStrategy
的详细分析请参考Spring Security 源码之 SessionAuthenticationStrategy
代码如下所示:
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
// 确保filter只执行一次
if (request.getAttribute(FILTER_APPLIED) != null) {
chain.doFilter(request, response);
return;
}
request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
// 如果是新认证的用户securityContextRepository还没有保存SecurityContext
if (!securityContextRepository.containsContext(request)) {
// 获取SecurityContextHolder已保存的authentication
Authentication authentication = SecurityContextHolder.getContext()
.getAuthentication();
// 如果用户已登录,且不是匿名登录
if (authentication != null && !trustResolver.isAnonymous(authentication)) {
// The user has been authenticated during the current request, so call the
// session strategy
try {
// 调用sessionStrategy的认证成功相关逻辑
sessionAuthenticationStrategy.onAuthentication(authentication,
request, response);
}
catch (SessionAuthenticationException e) {
// The session strategy can reject the authentication
logger.debug(
"SessionAuthenticationStrategy rejected the authentication object",
e);
// 如果遇到错误,清空SecurityContext,调用认证失败逻辑
SecurityContextHolder.clearContext();
failureHandler.onAuthenticationFailure(request, response, e);
return;
}
// Eagerly save the security context to make it available for any possible
// re-entrant
// requests which may occur before the current request completes.
// SEC-1396.
// 储存securityContext到repository
securityContextRepository.saveContext(SecurityContextHolder.getContext(),
request, response);
}
else {
// No security context or authentication present. Check for a session
// timeout
// 如果session已失效
if (request.getRequestedSessionId() != null
&& !request.isRequestedSessionIdValid()) {
if (logger.isDebugEnabled()) {
logger.debug("Requested session ID "
+ request.getRequestedSessionId() + " is invalid.");
}
// 调用session失效逻辑,跳转页面到指定URL
if (invalidSessionStrategy != null) {
invalidSessionStrategy
.onInvalidSessionDetected(request, response);
return;
}
}
}
}
chain.doFilter(request, response);
}
注意:本人在阅读此处代码时有个疑问,AbstractAuthenticationProcessingFilter
中也调用了SessionAuthenticationStrategy
的onauthentication
方法,感觉和SessionManagementFilter
的逻辑有重复。AbstractAuthenticationProcessingFilter
相关代码如下所示:
private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
// ...
}
try {
// ...
// 注意,这里也调用了sessionStrategy的onAuthentication方法
this.sessionStrategy.onAuthentication(authenticationResult, request, response);
// Authentication success
if (this.continueChainBeforeSuccessfulAuthentication) {
chain.doFilter(request, response);
}
successfulAuthentication(request, response, chain, authenticationResult);
}
// ...
}
我们注意到上面的代码中有一个变量continueChainBeforeSuccessfulAuthentication
,如果这个变量为false,不会再调用chain.doFilter
,即后面的filter不会再调用。SessionManagementFilter
位于AbstractAuthenticationProcessingFilter
,自然不会被调用。变量continueChainBeforeSuccessfulAuthentication
源码中的解释如下:
/**
* Indicates if the filter chain should be continued prior to delegation to
* {@link #successfulAuthentication(HttpServletRequest, HttpServletResponse, FilterChain, Authentication)}
* , which may be useful in certain environment (such as Tapestry applications).
* Defaults to <code>false</code>.
*/
这个变量表示认证成功后,调用successfulAuthentication
方法前是否调用后面的filter链,在Tapestry应用中可能会用到(我也不清楚这个是什么)。但是它的默认值为false,不会调用后面的filter。
本文为原创内容,欢迎大家讨论、批评指正与转载。转载时请注明出处。
网友评论