认证流程
认证流程是在 UsernamePasswordAuthenticationFilter 过滤器中处理的,具体流程如下所示:
UsernamePasswordAuthenticationFilter 源码
查看源码我们首先从过滤器的 doFilter() 方法看起,它实现在其抽象父类AbstractAuthenticationProcessingFilter 中,查看相关源码:
首先在子类UsernamePasswordAuthenticationFilter的空参构造器中调用了父类的构造器:将POST信息传给了父类的属性
调用了父类的构造器 将POST信息传给了父类的属性在父类的dofilter中调用了requiresAuthentication判断是否为post请求:
1. 判断该请求是否为POST方式的登陆表单提交请求,如果不是则直接放行,进入下一个过滤器
2. 放行后,调用了父类的接口attemptAuthentication,在没重写前调用的是子类UsernamePasswordAuthenticationFilter的attemptAuthentication()方法(也就是我们会重写的方法,为了获取表单提交过来的数据,并将用户的信息封装到Authentication中去)
在UsernamePasswordAuthenticationFilter子类中它是这样的:
判断是否为post提交,获取表单提交过来的用户名和密码封装到UsernamePasswordAuthenticationToken中去,表示为一个未认证的对象UsernamePasswordAuthenticationToken(附录一介绍)。并将请求的一些属性信息例如session等,封装到该UsernamePasswordAuthenticationToken对象中。调用ProvideManager中的authenticate方法进行身份验证(调用的是自己编写的UserDetailsService进行认证)(附录二介绍)
我们重写后是这样的:
3. Session策略处理,如果配置了用户Session最大并发数,就是在此处进行判断并处理
4. 默认的continueChainBeforeSuccessfulAuthentication为false,所以认证成功后不进入下一个过滤器
5. 认证成功调用successfulAuthentication,认证失败在catch中处理unsuccessfulAuthentication(),这两个方法也是我们重写过的。(重写前代码见附录三)
重写后为:
附录一 UsernamePasswordAuthenticationToken
创建的 UsernamePasswordAuthenticationToken 是Authentication 接口的实现类,该类有两个构造器,一个用于封装前端请求传入的未认证的用户信息,一个用于封装认证成功后的用户信息:
而它的父类AbstractAuthenticationToken实现了Authentication接口
Authentication 接口的实现类用于存储用户认证信息,查看该接口具体定义:
附录二:ProviderManager 源码
return this.getAuthenticationManager().authenticate(authRequest);
首先调用到UsernamePasswordAuthenticationFilter的父类AbstractAuthenticationProcessingFilter的方法getAuthenticationManager()获取到在AbstractAuthenticationProcessingFilter中的AuthenticationManager的对象authenticationManager,通过authenticationManager调用authenticate()方法。
authenticate()是AuthenticationManager接口的一个方法,实现类如下,但这里调用的是ProviderManager中的方法
上述过程中,UsernamePasswordAuthenticationFilter 过滤器的attemptAuthentication() 将未认证的 Authentication 对象传入ProviderManager 类的 authenticate() 方法进行身份认证。
ProviderManager 是 AuthenticationManager 接口的实现类,该接口是认证相关的核心接口,也是认证的入口。在实际开发中,我们可能有多种不同的认证方式,例如:用户名+密码、邮箱+密码、手机号+验证码等,而这些认证方式的入口始终只有一个,那就是AuthenticationManager。在该接口的常用实现类 ProviderManager 内部会维护一个List<AuthenticationProvider>列表,存放多种认证方式,实际上这是委托者模式(Delegate)的应用。每种认证方式对应着一个 AuthenticationProvider,AuthenticationManager 根据认证方式的不同(根据传入的 Authentication 类型判断)委托对应的 AuthenticationProvider 进行用户认证。
上述认证成功之后的(6)过程,调用 CredentialsContainer 接口定义的eraseCredentials() 方法去除敏感信息。查看UsernamePasswordAuthenticationToken 实现的 eraseCredentials() 方法,该方法实现在其父类中:
附录三:认证成功/失败处理
上述过程就是认证流程的最核心部分,接下来重新回到UsernamePasswordAuthenticationFilter 过滤器的 doFilter() 方法,查看认证成功/失败的处理:
查看 successfulAuthentication()和unsuccessfulAuthentication()方法源码
网友评论