SpringSecurity 密码验证流程

简介: 一、通过debug源码,解析,更加清楚的了解核心的原理,出现问题可以更好的解决 二、密码验证流程 1 默认使用 UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter 执行方法: pu.

一、通过debug源码,解析,更加清楚的了解核心的原理,出现问题可以更好的解决

二、密码验证流程

1 默认使用 UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter

  • 执行方法:

    public Authentication attemptAuthentication(HttpServletRequest request,
       HttpServletResponse response) throws AuthenticationException {
        if (postOnly && !request.getMethod().equals("POST")) {
       throw new AuthenticationServiceException(
               "Authentication method not supported: " + request.getMethod());
        }
        String username = obtainUsername(request);
        String password = obtainPassword(request);
        if (username == null) {
       username = "";
        }
        if (password == null) {
       password = "";
        }
        username = username.trim();
        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
           username, password);
        // Allow subclasses to set the "details" property
        setDetails(request, authRequest); (这里最终是AbstractAuthenticationToken)
        return this.getAuthenticationManager().authenticate(authRequest);
    } 

2 return this.getAuthenticationManager().authenticate(authRequest); 执行这个方法后,跳入到 AuthenticationManager 这个接口,以其一个实现类来实现这个方法。

   Authentication authenticate(Authentication authentication) throws AuthenticationException;

3 ProviderManager implements AuthenticationManager, MessageSourceAware,InitializingBean

    public Authentication authenticate(Authentication authentication)
               throws AuthenticationException {
           Class<? extends Authentication> toTest = authentication.getClass();
           AuthenticationException lastException = null;
           Authentication result = null;
           boolean debug = logger.isDebugEnabled(); 
           --AuthenticationProvider 校验的是这个对象
           for (AuthenticationProvider provider : getProviders()) {
               if (!provider.supports(toTest)) {
                   continue;
               }
               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);
                   // SEC-546: Avoid polling additional providers if auth failure is due to
                   // invalid account status
                   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) {
                   // ignore as we will throw below if no other exception occurred prior to
                   // calling parent and the parent
                   // may throw ProviderNotFound even though a provider in the child already
                   // handled the request
               }
               catch (AuthenticationException e) {
                   lastException = e;
               }
           }
           if (result != null) {
               if (eraseCredentialsAfterAuthentication
                       && (result instanceof CredentialsContainer)) {
                   // Authentication is complete. Remove credentials and other secret data
                   // from authentication
                   ((CredentialsContainer) result).eraseCredentials();
               }
               eventPublisher.publishAuthenticationSuccess(result);
               return result;
           }
           // Parent was null, or didn't authenticate (or throw an exception)
           if (lastException == null) {
               lastException = new ProviderNotFoundException(messages.getMessage(
                       "ProviderManager.providerNotFound",
                       new Object[] { toTest.getName() },
                       "No AuthenticationProvider found for {0}"));
           }
           prepareException(lastException, authentication);
           throw lastException;
    }

4 进入 public interface AuthenticationProvider

    Authentication authenticate(Authentication authentication) throws AuthenticationException;

5 进入 abstract class AbstractUserDetailsAuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware,实现了AuthenticationProvider 接口的authenticate(authentication)方法

public Authentication authenticate(Authentication authentication)
            throws AuthenticationException {
        Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication,
                messages.getMessage(
                        "AbstractUserDetailsAuthenticationProvider.onlySupports",
                        "Only UsernamePasswordAuthenticationToken is supported"));
        // Determine username
        String username = (authentication.getPrincipal() == null) ? "NONE_PROVIDED": authentication.getName();
        boolean cacheWasUsed = true;
        UserDetails user = this.userCache.getUserFromCache(username);
        if (user == null) {
            cacheWasUsed = false;
            try {
                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) {
                // There was a problem, so try again after checking
                // we're using latest data (i.e. not from the cache)
                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 abstract void additionalAuthenticationChecks(UserDetails userDetails,UsernamePasswordAuthenticationToken authentication)
         throws AuthenticationException;

6 通过实现该抽象类的子类 class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider,重写 additionalAuthenticationChecks方法

protected void additionalAuthenticationChecks(UserDetails userDetails,
            UsernamePasswordAuthenticationToken authentication)
            throws AuthenticationException {
        Object salt = null;
        if (this.saltSource != null) {
            salt = this.saltSource.getSalt(userDetails);
        }
        if (authentication.getCredentials() == null) {
            logger.debug("Authentication failed: no credentials provided");
            throw new BadCredentialsException(messages.getMessage(
                    "AbstractUserDetailsAuthenticationProvider.badCredentials",
                    "Bad credentials"));
        }
        String presentedPassword = authentication.getCredentials().toString();
        //验证密码, passwordEncoder 是客户端穿回来的密码,userDetails.getPassword()是数据库中的密码
        if (!passwordEncoder.isPasswordValid(userDetails.getPassword(),presentedPassword, salt)) {
            logger.debug("Authentication failed: password does not match stored value");
            throw new BadCredentialsException(messages.getMessage(
                    "AbstractUserDetailsAuthenticationProvider.badCredentials",
                    "Bad credentials"));
        }
    }

三、其他有关SpringSecurity的笔记,包括核心认识,demo地址

SpringSecurity初步学习

相关文章
|
25天前
|
NoSQL Java Redis
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
这篇文章介绍了如何使用Spring Boot整合Apache Shiro框架进行后端开发,包括认证和授权流程,并使用Redis存储Token以及MD5加密用户密码。
22 0
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
|
3月前
|
SQL 前端开发 Java
springboot项目中使用shiro实现用户登录以及权限的验证
这篇文章详细介绍了如何在Spring Boot项目中集成Apache Shiro框架来实现用户登录和权限验证,包括项目依赖配置、数据库连接、实体类定义、控制器、服务层、Mapper层以及前端页面的实现,并展示了实际效果和过滤器代码。
springboot项目中使用shiro实现用户登录以及权限的验证
|
安全 Java 数据安全/隐私保护
SpringSecurity 认证流程
通过了解SpringSecurity核心组件后,就可以进一步了解其认证的实现流程了。
105 0
|
安全 Java 数据库
SpringSecurity-4-认证流程源码解析
SpringSecurity-4-认证流程源码解析
76 0
|
安全 Java 数据库连接
四.SpringSecurity基础-自定义登录流程
SpringSecurity基础-自定义登录流程
|
6月前
|
API 数据安全/隐私保护
SpringSecurity结合JwtToken验证(后端部分)
SpringSecurity结合JwtToken验证(后端部分)
127 0
SpringSecurity结合JwtToken验证(后端部分)
|
6月前
|
SQL 安全 前端开发
Security登录认证流程分析
Security登录认证流程分析
67 5
|
存储 安全 Java
二.SpringSecurity基础-简单登录实现
SpringSecurity基础-简单登录实现
|
存储 安全 Java
SpringSecurity基础-简单登录实现
1.SpringSecurity介绍 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
96 0
|
安全 Java Apache
Springboot整合shiro:实现用户登录和权限验证
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。当然类型大家也可以使用spring security;因为我平时开发的项目都是中小型的,所以使用shiro对于业务来说已经够用了,那么下面是我整理的整合记录;
154 0