最近看了如何获取用户登陆的额外信息,有一个主要步骤就是自定义WebAuthenticationDetails。今天来分析一下自定义WebAuthenticationDetails的原理,和spring security默认的WebAuthenticationDetails流程是什么样的。
如何产生WebAuthenticationDetails

http.formLogin()的时候就是初始化FormLoginConfigurer,它在构造方法中做了两件事情:1、初始化父类new UsernamePasswordAuthenticationFilter() 新建一个filter。2、把新建的Filter通过父类的构造方法传递给父类AbstractAuthenticationFilterConfigurer。
public final class FormLoginConfigurer {
public FormLoginConfigurer() {
super(new UsernamePasswordAuthenticationFilter(), null);
usernameParameter("username");
passwordParameter("password");
}
}
public abstract class AbstractAuthenticationFilterConfigurer {
private F authFilter;
protected AbstractAuthenticationFilterConfigurer(F authenticationFilter,
String defaultLoginProcessingUrl) {
this();
this.authFilter = authenticationFilter;
if (defaultLoginProcessingUrl != null) {
loginProcessingUrl(defaultLoginProcessingUrl);
}
}
//这里是http.formLogin().authenticationDetailsSource()自定义DetailsSource的入口
public final T authenticationDetailsSource(
AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource) {
this.authenticationDetailsSource = authenticationDetailsSource;
return getSelf();
}
}
可以看到上面已经new出来一个Filter,并且AbstractAuthenticationFilterConfigurer对象绑定。Configurer对象会在config()方法中设置Filter的各个属性。那么Filter中的AuthenticationDetailsSource是合适设置的呢?
UsernamePasswordAuthenticationFilter在初始化时候会调用父类构造器,父类AbstractAuthenticationProcessingFilter在初始化的时候,默认会有一个protected AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();的实现。
public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public UsernamePasswordAuthenticationFilter() {
super(new AntPathRequestMatcher("/login", "POST"));
}
}
public abstract class AbstractAuthenticationProcessingFilter{
protected AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
}
public abstract class AbstractAuthenticationFilterConfigurer{
public void configure(B http) throws Exception {
//这里就是我们给AbstractAuthenticationProcessingFilter设置自定义DetailsSource的入口
if (authenticationDetailsSource != null) {
authFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
}
}
现在WebAuthenticationDetailsSource有了,WebAuthenticationDetails是何时产生的呢?
在认证流程进入Filter的链接链时,AbstractAuthenticationProcessingFilter.doFilter()中调用attemptAuthentication()方法,该方法由子类UsernamePasswordAuthenticationFilter实现。子类的attemptAuthentication()方法中调用setDetails()方法。该方法给UsernamePasswordAuthenticationToken填充详情的时候产生了WebAuthenticationDetails。
public class UsernamePasswordAuthenticationFilter {
protected void setDetails(HttpServletRequest request,
UsernamePasswordAuthenticationToken authRequest) {
//这里调用authenticationDetailsSource的build就构建了一个WebAuthenticationDetail对象
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}
}