• springSecurity登录验证分析——AbstractUserDetailsAuthenticationProvider


    AbstractUserDetailsAuthenticationProvider类位于org.springframework.security.authentication.dao包下,在

    org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter中被调用,

    该类的public Authentication authenticate(Authentication authentication) throws AuthenticationException方法百常重要,通过这段代码能详细了解整个验证的过程,下面对该方法的代码分段进行说明:

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

        //要求传入的authentication对象必须是UsernamePasswordAuthenticationToken类或其子类的实例

    (2)  

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

    //从authentication中取出登录名

    (3) boolean cacheWasUsed = true;
            UserDetails user = this.userCache.getUserFromCache(username);

    //默认情况下从缓存中(UserCache接口实现)取出用户信息

    (4)

    if (user == null) {

    //如果从内存中取不到用户,则设置cacheWasUsed 为false,供后面使用

       cacheWasUsed = false;

                try {

          //retrieveUser是抽象方法,通过子类来实现获取用户的信息,以UserDetails接口形式返回
                    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");
            }

    (5)

        try {

                //preAuthenticationChecks和additionalAuthenticationChecks这是UserDetailsChecker接口的实现类

                //验证帐号是否锁定\是否禁用\帐号是否到期
                preAuthenticationChecks.check(user);

        //由子类来完成更进一步的验证
                additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
            } catch (AuthenticationException exception) {

               //下面这段代码体现了老外的细腻之处,意思是说如果在调用某个UserDetailsChecker接口的实现类验证失败后,就判断下用户信息是否从内存中得到,如果之前是从内存中得到的用户信息,那么考虑到可能数据是不实时的,就重新通过retrieveUser方法去取出用户信息,再次重复进行检查验证
                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;
                }
            }

    (6)  //在spring的框架设计中经常能看到这样的前置处理和后置处理,此处后置处理只是判断了下用户的密码是否过期,如过期则记入日志

           postAuthenticationChecks.check(user);

             //如果没有缓存则进行缓存,则处的userCache是由NullUserCache类实现的,名如其义,该类的putUserInCache没做任何事

             if (!cacheWasUsed) {
                this.userCache.putUserInCache(user);
            }

     (7)

    //以下代码主要是把用户的信息和之前用户提交的认证信息重新组合成一个authentication实例返回,返回类是

    UsernamePasswordAuthenticationToken类的实例

             Object principalToReturn = user;

            if (forcePrincipalAsString) {
                principalToReturn = user.getUsername();
            }

            return createSuccessAuthentication(principalToReturn, authentication, user);

    -----------------------------------------------------------------------------------

    代码分析到此,另外再附上类图方便理解。

  • 相关阅读:
    Atmel Studio 烧录 Atmega328P(Arduiono)
    JSP内置对象详解及示例
    Hash Map 详细解释及示例
    19年双非学长逆袭985考研经验贴
    camelCase命名规范
    开始我的编程之旅!
    【转】堆和栈的区别
    现场编写类似strstr/strcpy函数
    【转】C++多态篇1一静态联编,动态联编、虚函数与虚函数表vtable
    【转】TCP协议中的三次握手和四次挥手(图解)
  • 原文地址:https://www.cnblogs.com/hzhuxin/p/2287564.html
Copyright © 2020-2023  润新知