Spring Security为我们提供了一个匿名用户的功能,我们可以基于此很容易的实现匿名用户的单独控制,使我们的站点轻松拥有游客用户的功能;
如果开启了匿名用户的功能,按照Spring Security Filter的执行顺序,AnonymousAuthenticationFilter在ExceptionTranslationFilter的前面,在各种认证机制和RememberMeAuthenticationFilter的后面。也就是说,这是最后一步给可能给用户授权的处理步骤;
下面是Configurer#init和Configurer#configure方法:
@Override
public void init(H http) throws Exception {
if (authenticationProvider == null) {
authenticationProvider = new AnonymousAuthenticationProvider(getKey());
}
if (authenticationFilter == null) {
authenticationFilter = new AnonymousAuthenticationFilter(getKey(), principal,
authorities);
}
authenticationProvider = postProcess(authenticationProvider);
http.authenticationProvider(authenticationProvider);
}
@Override
public void configure(H http) throws Exception {
authenticationFilter.afterPropertiesSet();
http.addFilter(authenticationFilter);
}
可以看到,开启Anonymous之后,会new一个AnonymousAuthenticationProvider添加到当前的HttpSecurityBuilder配置中,专门用来处理带有AnonymousAuthenticationToken的请求,new一个AnonymousAuthenticationFilter加到Filter Chain中,用来在合适的条件下往当前请求中填充一个AnonymousAuthenticationToken对象。
从AnonymousAuthenticationFilter可以看出Spring Security对匿名用户的处理过程;
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
if (SecurityContextHolder.getContext().getAuthentication() == null) {
SecurityContextHolder.getContext().setAuthentication(
createAuthentication((HttpServletRequest) req));
if (logger.isDebugEnabled()) {
logger.debug("Populated SecurityContextHolder with anonymous token: '"
+ SecurityContextHolder.getContext().getAuthentication() + "'");
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("SecurityContextHolder not populated with anonymous token, as it already contained: '"
+ SecurityContextHolder.getContext().getAuthentication() + "'");
}
}
chain.doFilter(req, res);
}
protected Authentication createAuthentication(HttpServletRequest request) {
AnonymousAuthenticationToken auth = new AnonymousAuthenticationToken(key,
principal, authorities);
auth.setDetails(authenticationDetailsSource.buildDetails(request));
return auth;
}
如果web request到了这个Filter,SecurityContextHolder中还没有Authentication,创建一个AnonymousAuthenticationToken。AnonymousAuthenticationToken里面的信息包括一个key(类似于user表的主键),一个principal对象和一个权限列表authorities,这三个信息是给Spring Security应用的配置信息。
在AnonymousAuthenticationFilter里这么做的好处是,请求过了这个Filter之后,就可以当作一个正常的带有Authentication信息的请求的,后面的认证授权等操作都不用对其做特殊处理。
大家可以根据这个思路,分析下非常类似的RememberMe功能。
参考:
Spring Security(11)——匿名认证
Spring Security学习笔记之RememberMeAuthenticationFilter