1.认证流程流程
经过断点调试,能够看到在UsernamepasswordAuthenticationFilter中构造了一个
UsernamePasswordAuthenticationToken对象spring
打开UsernamePasswordAuthenticationToken可得知,该实现类是Authentication的子类,由于Authentication是封装了用户的信息。
在该构造函数中,其中super(null)是调用了父类的方法
,
父类的方法以下:app
public AbstractAuthenticationToken(Collection<? extends GrantedAuthority> authorities) { if (authorities == null) { //为空时,须要赋个默认的权限,由于此时还未进行身份认证 this.authorities = AuthorityUtils.NO_AUTHORITIES; return; } for (GrantedAuthority a : authorities) { if (a == null) { throw new IllegalArgumentException( "Authorities collection cannot contain any null elements"); } } ArrayList<GrantedAuthority> temp = new ArrayList<GrantedAuthority>( authorities.size()); temp.addAll(authorities); this.authorities = Collections.unmodifiableList(temp); }
setAuthenticated(false) 表明当前存进去的principal/credentials是否通过身份认证,此时确定是没有的。ide
setDetails(request, authRequest);
该方法会把请求的一些信息设置到UsernamePasswordAuthenticationToken里面去,包括当前发起请求的IP,Session等函数
return this.getAuthenticationManager().authenticate(authRequest); //往AuthenticationManager靠拢
AuthenticationManager该类自己不包含校验的逻辑,它的做用是用来管理AuthenticationProvider。
该方法会请求进入:ProviderManager.authenticate()方法,该类实现了AuthenticationManager接口post
public Authentication authenticate(Authentication authentication) throws AuthenticationException { Class<? extends Authentication> toTest = authentication.getClass(); AuthenticationException lastException = null; Authentication result = null; boolean debug = logger.isDebugEnabled(); for (AuthenticationProvider provider : getProviders()) { // if (!provider.supports(toTest)) { continue; } /* getProviders() 拿到全部的AuthenticationProvider,校验逻辑都是在Provider中 由于不一样的登陆方式,它的认证逻辑是不通 的,目前使用的用户名+密码的方式,后续还会有第三方登陆,手机 号验证码登陆等,provider.supports(toTest)是否支持当前的登陆方式(判断) 对于用户名密码方式,它传递的token是:UsernamePasswordAuthenticationToken,而对于第三方登陆时的验证方式则是SocialAuthenticationToken */ if (debug) { logger.debug("Authentication attempt using " + provider.getClass().getName()); } try { //具体执行校验逻辑 result = provider.authenticate(authentication); if (result != null) { copyDetails(authentication, result); break; } } catch (AccountStatusException e) { prepareException(e, authentication); throw e; } catch (InternalAuthenticationServiceException e) { prepareException(e, authentication); throw e; } catch (AuthenticationException e) { lastException = e; } } if (result == null && parent != null) { // Allow the parent to try. try { result = parent.authenticate(authentication); } catch (ProviderNotFoundException e) { } catch (AuthenticationException e) { lastException = e; } } if (result != null) { if (eraseCredentialsAfterAuthentication && (result instanceof CredentialsContainer)) { ((CredentialsContainer) result).eraseCredentials(); } eventPublisher.publishAuthenticationSuccess(result); return result; } if (lastException == null) { lastException = new ProviderNotFoundException(messages.getMessage( "ProviderManager.providerNotFound", new Object[] { toTest.getName() }, "No AuthenticationProvider found for {0}")); } prepareException(lastException, authentication); throw lastException; }
provider.authenticate()实现类是写在AuthenticationProvider的实现类AbstractUserDetailsAuthenticationProvider中this
public Authentication authenticate(Authentication authentication) throws AuthenticationException { Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication, 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 { //获取用户信息,具体实现类在:DaoAuthenticationProvider.retrieveUser() user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication); } catch (UsernameNotFoundException notFound) { logger.debug("User '" + username + "' not found"); if (hideUserNotFoundExceptions) { throw new BadCredentialsException(messages.getMessage( "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); } else { throw notFound; } } Assert.notNull(user, "retrieveUser returned null - a violation of the interface contract"); } try { preAuthenticationChecks.check(user); additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication); } catch (AuthenticationException exception) { if (cacheWasUsed) { cacheWasUsed = false; user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication); preAuthenticationChecks.check(user); additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication); } else { throw exception; } } postAuthenticationChecks.check(user); if (!cacheWasUsed) { this.userCache.putUserInCache(user); } Object principalToReturn = user; if (forcePrincipalAsString) { principalToReturn = user.getUsername(); } return createSuccessAuthentication(principalToReturn, authentication, user); }
protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { UserDetails loadedUser; try { loadedUser = this.getUserDetailsService().loadUserByUsername(username); /** getUserDetailService在调用咱们提供的UserDetailService的实现,也就是:MyUserDetailsService */ } catch (UsernameNotFoundException notFound) { if (authentication.getCredentials() != null) { String presentedPassword = authentication.getCredentials().toString(); passwordEncoder.isPasswordValid(userNotFoundEncodedPassword, presentedPassword, null); } throw notFound; } catch (Exception repositoryProblem) { throw new InternalAuthenticationServiceException( repositoryProblem.getMessage(), repositoryProblem); } if (loadedUser == null) { throw new InternalAuthenticationServiceException( "UserDetailsService returned null, which is an interface contract violation"); } return loadedUser; }
拿到用户信息以后,回到AbstractUserDetailsAuthenticationProviderdebug
try { preAuthenticationChecks.check(user); additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication); //在dao里校验密码是否匹配 }
它会预检查用户是否过时,是否禁用,以后检查密码是否匹配。
预检查以后还会有后置检查3d
postAuthenticationChecks.check(user); //
全部检查都经过,就会认为用户的认证是成功的。调试
return createSuccessAuthentication(principalToReturn, authentication, user); protected Authentication createSuccessAuthentication(Object principal, Authentication authentication, UserDetails user) { UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken( principal, authentication.getCredentials(), authoritiesMapper.mapAuthorities(user.getAuthorities())); result.setDetails(authentication.getDetails()); return result; }
再次new 了UsernamePasswordAuthenticationToken对象,区别再与构造方法不一样,传递的参数不一样,这个时候权限,用户信息都已经拿到code
2.认证结果如何在多个请求之间共享
3.获取用户认证的信息