zoukankan      html  css  js  c++  java
  • shiro源码分析-认证过程

    一。shiro的认证过程源码分析

    1.程序登录入口,页面传递地参数userName,password ,loginType3个参数,用 LoginUser 对象接收。loginType 为登录方式,因为我这里有多种登录方式,因此用这个字段来区分。不同的登录方式,采用不同的token封装登录信息。登录的过程就是调用Subject 的login方法,参数为封装登录信息的token。shiro用抛异常的方式来反馈登录结果,不同的异常代表不同的反馈结果。

    public ResultBean login(LoginUser loginUser) {
            String userName = loginUser.getUserName();
            String password = loginUser.getPassword();
            String loginType = loginUser.getLoginType();
    
            if (StringUtils.isAnyBlank(userName, password, loginType)) {
                return ResultBean.paramsError();
            }
    
            Subject subject = SecurityUtils.getSubject();
            AuthenticationToken token = null;
            if (PASSWORD_LOGIN.equals(loginType)) {
                token = new UsernamePasswordToken(userName, password);
            } else if (CODE_LOGIN.equals(loginType)) {
                token = new PhoneCodeToken(userName, password);
            } else {
                return ResultBean.failure("不支持的登录方式");
            }
    
            String errorMsg = "";
            try {
                subject.login(token);return ResultBean.success(user);
            } catch (UnknownAccountException e) {
                errorMsg = "无效账户";
            } catch (IncorrectCredentialsException e) {
                errorMsg = "密码错误";
            } catch (CodeErrorException e) {
                errorMsg = "验证码错误/已过期";
            } catch (LockedAccountException e) {
                errorMsg = "用户已冻结";
            } catch (AuthenticationException e) {
                errorMsg = "登录异常,请联系管理员";
                logger.error("登录异常,{}", e.getMessage());
            }
            return ResultBean.failure(errorMsg);
        }
    View Code

    2.重点看subject.login(token)方法。跟踪进去,看到DelegatingSubject类的login()方法。DelegatingSubject为subject接口的实现类。可以看到,在login()方法里面,调用SecurityManager的login()方法。

    3.跟踪进去,到了DefaultSecurityManager的login()方法。此方法中调用父类AuthenticatingSecurityManager的authenticate(token)方法。返回AuthenticationInfo对象,这个对象包涵认证信息。

     4.进到AuthenticatingSecurityManager的authenticate(token)方法。this.authenticator对象就是shiro的认证器,它是个接口,默认实现是ModularRealmAuthenticator。

     

    5.继续跟进。进入到AbstractAuthenticator的authenticate(token)方法,此类是ModularRealmAuthenticator的父类。方法中继续调用doAuthenticate(token)方法。

     6.继续跟进。就到了ModularRealmAuthenticator。这个类就是shiro认证器的默认实现。看doAuthenticate(token)方法。shiro的realm部分,是用户自定义实现部分,一般有几种登录方式,就写几个realm。shiro中一个realm和多个realm的认证策略是不一样,因此这里一个条件判断,判断realm的个数。简单点,我们看doSingleRealmAuthentication()方法。

    多个realm中,就有认证策略的问题。AuthenticationStrategy这个接口,就是认证策略的接口。后面再讲。

     7.看ModularRealmAuthenticator的doSingleRealmAuthentication(realm,token)方法。这里面就调用realm的getAuthenticationInfo(token)方法。这里的realm就是我们自己实现的realm.

    8.继续跟进。 进入到AuthenticatingRealm的getAuthenticationInfo(token)方法。AuthenticatingRealm也就是我们自己实现的realm的父类。该方法中首先从缓存中取认证信息,如果没有就调用我们定义的realm的doGetAuthenticationInfo(token)方法。

     9.此时就可以到我们自己实现的realm了。在自定义的doGetAuthenticationInfo(token)中,我们调用服务层,获取用户信息。然后构建SimpleAuthenticationInfo对象返回。该对象中第一个参数,就是主体信息,可以是user对象,也可以是一个用户名。后面我们用subject.getPrincipal(),返回值就是这个值。第二个参数就是密码,第三个参数就是散列散发的盐。第四个参数就是当前Realm的名字,可以用通过方法getName()获取。

     @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
    
            String username = usernamePasswordToken.getUsername();
    
            UserVO user = userService.fetchOneByUserName(username);
    
            if (user == null) {
                throw new UnknownAccountException();
            }
    
            //帐号被锁定
            if ("0".equals(user.getState())) {
                throw new LockedAccountException();
            }
    
            return new SimpleAuthenticationInfo(
                    user,
                    user.getPassword(),
                    ByteSource.Util.bytes(user.getCredentialsSalt()),
                    getName()
            );
        }
    View Code

     10.然后一路返回AuthenticationInfo对象。里面就包涵,密码,盐等认证信息。返回到AuthenticatingRealm的getAuthenticationInfo(token)方法。下一步就是调用密码匹配器验证密码了。

     11.进入到assertCredentialsMatch(token, info)。第一个参数就是登录信息,第二个参数就是realm返回的认证信息。然后就调用密码匹配器去匹配。因为shiro是根据抛出异常来反馈匹配结果,所以没有返回值。如果匹配正确,登录过程就完成了,如果匹配错误,就会抛出具体的异常。

     12.这里列举了几个具体的异常。CodeErrorException是我自己添加的,用来抛出验证码登录时,验证码错误的异常。

  • 相关阅读:
    mac 环境下adb的安装
    iOS开发Swift版本
    UILabel-Swift
    Android应用上架
    Android应用开发
    andriod
    Android 6.0 更新包与已安装应用的签名不一致
    苹果手机怎么录屏 iOS12设置录屏
    Siri语音唤醒的开启与语音矫正
    Git的工作流程
  • 原文地址:https://www.cnblogs.com/step-and-step/p/13304868.html
Copyright © 2011-2022 走看看