用debug思想去解释shiro登录原理

上一篇Karley Blog:Karley的Java个人博客全纪录之SpringBoot整合Shiro实现登录注册但是只有怎么做,没有为什么,今天康康shiro是怎么做登录的。

  1. 首先在UserServiceImpl.java的封装用户登录数据
    上面打个断点。然后登录。
    在这里插入图片描述
    然后断点获得了在这里插入图片描述
    subject里面有principals,有securityManager:
    在这里插入图片描述
    securityManager里面有authenticator,realms,sessionManager,rememberMeManager,还有其他以后也会用到的cacheManager,authorizer等
    在这里插入图片描述
  2. 走到了login方法
    在这里插入图片描述
    在try方法体中如果出现异常将会进行捕获。点进去login方法的接口Subject.class,发现里面有一个login方法,这个方法throws了一个认证异常:
void login(AuthenticationToken var1) throws AuthenticationException;

点进去login的实体类(Delegating.class)中

    public void login(AuthenticationToken token) throws AuthenticationException {
        this.clearRunAsIdentitiesInternal();
        Subject subject = this.securityManager.login(this, token);
        String host = null;
        PrincipalCollection principals;
        if (subject instanceof DelegatingSubject) {
            DelegatingSubject delegating = (DelegatingSubject)subject;
            principals = delegating.principals;
            host = delegating.host;
        } else {
            principals = subject.getPrincipals();
        }

        if (principals != null && !principals.isEmpty()) {
            this.principals = principals;
            this.authenticated = true;
            if (token instanceof HostAuthenticationToken) {
                host = ((HostAuthenticationToken)token).getHost();
            }

            if (host != null) {
                this.host = host;
            }

            Session session = subject.getSession(false);
            if (session != null) {
                this.session = this.decorate(session);
            } else {
                this.session = null;
            }

        } else {
            String msg = "Principals returned from securityManager.login( token ) returned a null or empty value.  This value must be non null and populated with one or more elements.";
            throw new IllegalStateException(msg);
        }
    }

第一个**this.clearRunAsIdentitiesInternal();**是什么意思?点进去看,发现下面是一个私有方法:

    private void clearRunAsIdentitiesInternal() {
        try {
            this.clearRunAsIdentities();
        } catch (SessionException var2) {
            log.debug("Encountered session exception trying to clear 'runAs' identities during logout.  This can generally safely be ignored.", var2);
        }

    }

他在这里又try了一个this.clearRunAsIdentities();,继续点进去看:

    private void clearRunAsIdentities() {
        Session session = this.getSession(false);
        if (session != null) {
            session.removeAttribute(RUN_AS_PRINCIPALS_SESSION_KEY);
        }

    }

发现里面是一个控制session的方法体,如果session不为空,则移除session的Attribute。

重新看刚才的login方法,他主要进行了两个判断,一个是对当前login的subject进行判断是否是当前的subject,另一个是对principals判断是否为空,如果不为空再进行接下来的判断。

login方法的参数是token,所以在调用login的时候要传入token参数。

反观我们在UserRealm.java中验证密码使用这条语句

return new SimpleAuthenticationInfo(user,user.getPassword(),this.getName());

点进去SimpleAuthenticationInfo,这是一个接口类,里面有两个方法体

public interface AuthenticationInfo extends Serializable {
    PrincipalCollection getPrincipals();

    Object getCredentials();
}

在他们的实体类中SimpleAuthenticationInfo.class中这两个方法返回了principals和credentials。

    public PrincipalCollection getPrincipals() {
        return this.principals;
    }
    public Object getCredentials() {
        return this.credentials;
    }

实体类SimpleAuthenticationInfo.class继承了两个接口:MergableAuthenticationInfo, SaltedAuthenticationInfo

点进去接口MergableAuthenticationInfo.class里面只有一个方法:

public interface MergableAuthenticationInfo extends AuthenticationInfo {
    void merge(AuthenticationInfo var1);
}

点进去merge的实体类SimpleAuthenticationInfo.java:

    public void merge(AuthenticationInfo info) {
        if (info != null && info.getPrincipals() != null && !info.getPrincipals().isEmpty()) {
            if (this.principals == null) {
                this.principals = info.getPrincipals();
            } else {
                if (!(this.principals instanceof MutablePrincipalCollection)) {
                    this.principals = new SimplePrincipalCollection(this.principals);
                }

                ((MutablePrincipalCollection)this.principals).addAll(info.getPrincipals());
            }

            if (this.credentialsSalt == null && info instanceof SaltedAuthenticationInfo) {
                this.credentialsSalt = ((SaltedAuthenticationInfo)info).getCredentialsSalt();
            }

            Object thisCredentials = this.getCredentials();
            Object otherCredentials = info.getCredentials();
            if (otherCredentials != null) {
                if (thisCredentials == null) {
                    this.credentials = otherCredentials;
                } else {
                    if (!(thisCredentials instanceof Collection)) {
                        Set newSet = new HashSet();
                        newSet.add(thisCredentials);
                        this.setCredentials(newSet);
                    }

                    Collection credentialCollection = (Collection)this.getCredentials();
                    if (otherCredentials instanceof Collection) {
                        credentialCollection.addAll((Collection)otherCredentials);
                    } else {
                        credentialCollection.add(otherCredentials);
                    }

                }
            }
        }
    }

里面的逻辑是首先判断你的info和principals是否为空,判断你的principals是否发生变化,去判断参数是否加盐,下面就是密码的对比,密码对比的方式是通过哈希集合的方式进行对比,如果一个密码在哈希集合里面有值则密码正确。

目前大概就是这样,但是还没找到login方法和AuthenticationInfo.java之间的联系以及是如何抛出异常的。

欢迎大佬指正提点!!!

展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 深蓝海洋 设计师: CSDN官方博客
应支付0元
点击重新获取
扫码支付

支付成功即可阅读