写点什么

Spring Security 账号密码认证源码解析,java 项目开发全程实录第四版视频

用户头像
极客good
关注
发布于: 刚刚

private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {


// 判断当前过滤器能否处理该请求,如果不能,则交给下一个 filter 去处理


if (!requiresAuthentication(request, response)) {


chain.doFilter(request, response);


return;


}


try {


// 调用子类中的方法,创建 Authentication 实现类


Authentication authenticationResult = attemptAuthentication(request, response);


if (authenticationResult == null) {


// return immediately as subclass has indicated that it hasn't completed


return;


}


// 如果成功则做些 session 相关操作,例如将信息保存到 session


this.sessionStrategy.onAuthentication(authenticationResult, request, response);


// Authentication success


if (this.continueChainBeforeSuccessfulAuthentication) {


chain.doFilter(request, response);


}


successfulAuthentication(request, response, chain, authenticationResult);


}


catch (InternalAuthenticationServiceException failed) {


this.logger.error("An internal error occurred while trying to authenticate the user.", failed);


unsuccessfulAuthentication(request, response, failed);


}


catch (AuthenticationException ex) {


// Authentication failed


unsuccessfulAuthentication(request, response, ex);


}


}


[](


)2.doFilter 方法中调用了自身的 attemptAuthentication()方法





[](


)3.attemptAuthentication()方法中调用了 AuthenticationManager 接口实现类 ProviderManager 的 authenticate 方法。




(1)在 attemptAuthentication()方法中,只是将账号密码和一些请求信息封装在了一个类中,但并没有对权限,密码是否正确等进行认证,该方法就是用来进行认证管理的。


(2)AuthenticationManager 是一个接口,该接口中只有一个 authenticate 方法。


public interface AuthenticationManager {


Authentication authenticate(Authentication v


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


ar1) throws AuthenticationException;


}


(3)该接口的主要实现类为 ProviderManager,调用的就是该类的 authenticate 方法。该类有二个用于认证的成员变量:


private List<AuthenticationProvider> providers;


private AuthenticationManager parent;


AuthenticationProvider 是一个接口,是用来提供认证服务的,ProviderManager 只是用来管理认证服务的。


// 该接口有两个方法,该接口的实现类主要做认证的。


public interface AuthenticationProvider {


Authentication authenticate(Authentication var1) throws AuthenticationException;


// supports 是用来检测该类型的认证信息是否可以被自己处理。可以被处理则调用自身的 authenticate 方法。


boolean supports(Class<?> var1);


}


(4)ProviderManager 的 authenticate()方法源码关键部分如下:


public Authentication authenticate(Authentication authentication) throws AuthenticationException {


Class toTest = authentication.getClass();


Object lastException = null;


Authentication result = null;


boolean debug = logger.isDebugEnabled();


// 拿到全部的 provider


Iterator e = this.getProviders().iterator();


// 遍历 provider


while(e.hasNext()) {


AuthenticationProvider provider = (AuthenticationProvider)e.next();


// 挨着个的校验是否支持当前 token


if(provider.supports(toTest)) {


if(debug) {


logger.debug("Authentication attempt using " + provider.getClass().getName());


}


try {


// 找到后直接 break,并由当前 provider 来进行校验工作


result = provider.authenticate(authentication);


if(result != null) {


this.copyDetails(authentication, result);


break;


}


} catch (AccountStatusException var11) {


this.prepareException(var11, authentication);


throw var11;


} catch (InternalAuthenticationServiceException var12) {


this.prepareException(var12, authentication);


throw var12;


} catch (AuthenticationException var13) {


lastException = var13;


}


}


}


// 若没有一个支持,则尝试交给父类来执行


if(result == null && this.parent != null) {


try {


result = this.parent.authenticate(authentication);


} catch (ProviderNotFoundException var9) {


;


} catch (AuthenticationException var10) {


lastException = var10;


}


}


..........................


}


其中会遍历调用 AuthenticationProvider 实现类对象的 supports 方法,如果方法返回 true,则调用 AuthenticationProvider 实现类对象的 authenticate()方法,该方法是用来进行认证的。


如果该 ProviderManager 的 List<AuthenticationProvider> providers 都无法处理,则会调用该 ProviderManager 的 AuthenticationManager parent 的 authenticate 方法,流程一样。


[](


)4.AuthenticationManager 对象的 authenticate 方法中调用 AuthenticationProvider 接口实现类 DaoAuthenticationProvider 的 authenticate 方法




**(1) DaoAuthenticationProvider **


对于我们前面封装的 UsernamePasswordAuthenticationToken 对象,它的认证处理可以被 DaoAuthenticationProvider 类进行认证。


DaoAuthenticationProvider 类中其实没有定义 authenticate 方法,它是继承了父类 AbstractUserDetailsAuthenticationProvider 中的 authenticate 方法。


AbstractUserDetailsAuthenticationProvider 的 authenticate()方法源码如下:


// 实现了 AuthenticationProvider 接口


public abstract class AbstractUserDetailsAuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware {


public Authentication authenticate(Authentication authentication) throws AuthenticationException {


Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication, this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.onlySupports", "Only UsernamePasswordAuthenticationToken is supported"));


String username = authentication.getPrincipal() == null?"NONE_PROVIDED":authentication.getName();


boolean cacheWasUsed = true;


UserDetails user = this.userCache.getUserFromCache(username);


if(user == null) {


cacheWasUsed = false;


try {

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
Spring Security账号密码认证源码解析,java项目开发全程实录第四版视频