代码
- 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();
- // 如果配置了缓存,从缓存中去取以前存入的用户验证信息 - 这里是UserDetail,是服务器端存在数据库里的用户信息,这样就不用每次都去数据库中取了
- boolean cacheWasUsed = true;
- UserDetails user = this.userCache.getUserFromCache(username);
- //没有取到,设置标志位,下面会把这次取到的服务器端用户信息存入缓存中去
- if (user == null) {
- cacheWasUsed = false;
- try {//这里是调用UserDetailService去取用户数据库里信息的地方
- user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
- } catch (UsernameNotFoundException notFound) {
- 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");
- }
- if (!user.isAccountNonLocked()) {
- throw new LockedException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.locked",
- "User account is locked"));
- }
- if (!user.isEnabled()) {
- throw new DisabledException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.disabled",
- "User is disabled"));
- }
- if (!user.isAccountNonExpired()) {
- throw new AccountExpiredException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.expired",
- "User account has expired"));
- }
- // This check must come here, as we don't want to tell users
- // about account status unless they presented the correct credentials
- try {//这里是验证过程,在retrieveUser中从数据库中得到用户的信息,在additionalAuthenticationChecks中进行对比用户输入和服务器端的用户信息
- //如果验证通过,那么构造一个Authentication对象来让以后的授权使用,如果验证不通过,直接抛出异常结束鉴权过程
- additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
- } catch (AuthenticationException exception) {
- if (cacheWasUsed) {
- // There was a problem, so try again after checking
- // we're using latest data (ie not from the cache)
- cacheWasUsed = false;
- user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
- additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
- } else {
- throw exception;
- }
- }
- if (!user.isCredentialsNonExpired()) {
- throw new CredentialsExpiredException(messages.getMessage(
- "AbstractUserDetailsAuthenticationProvider.credentialsExpired", "User credentials have expired"));
- }
- //根据前面的缓存结果决定是不是要把当前的用户信息存入缓存以供下次验证使用
- if (!cacheWasUsed) {
- this.userCache.putUserInCache(user);
- }
- Object principalToReturn = user;
- if (forcePrincipalAsString) {
- principalToReturn = user.getUsername();
- }
- //最后返回Authentication记录了验证结果供以后的授权使用
- return createSuccessAuthentication(principalToReturn, authentication, user);
- }
- //这是是调用UserDetailService去加载服务器端用户信息的地方,从什么地方加载要看设置,这里我们假设由JdbcDaoImp来从数据中进行加载
- protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
- throws AuthenticationException {
- UserDetails loadedUser;
- //这里调用UserDetailService去从数据库中加载用户验证信息,同时返回从数据库中返回的信息,这些信息放到了UserDetails对象中去了
- try {
- loadedUser = this.getUserDetailsService().loadUserByUsername(username);
- } catch (DataAccessException repositoryProblem) {
- throw new AuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);
- }
- if (loadedUser == null) {
- throw new AuthenticationServiceException(
- "UserDetailsService returned null, which is an interface contract violation");
- }
- return loadedUser;
- }
下面我们重点分析一下JdbcDaoImp这个类来看看具体是怎样从数据库中得到用户信息的: