SpringSecurity源码导读(二)-WebAuthenticationDetails

1,616 阅读1分钟

最近看了如何获取用户登陆的额外信息,有一个主要步骤就是自定义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));
	}
}