Shiro鉴权流程

​ Shiro的登录动作是由Subject接口的 login(AuthenticationToken token) 方法进行的,而login()方法的只有DelegatingSubject 实现了这个方法。

public void login(AuthenticationToken token) throws AuthenticationException {
        clearRunAsIdentitiesInternal();
        Subject subject = securityManager.login(this, token);
  			// Omit the more code(省略更多代码,Omit : 省略)
}

​ 在 login() 方法中又调用了 SecurityManager 接口的 login 方法,该方法的实现由 DefaultSecurityManager 类实现。

public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException {
        AuthenticationInfo info;
        try {
          // 执行 认证方法(authenticate)
            info = authenticate(token);
        } catch (AuthenticationException ae) {
            // Omit the more code ···
        }
    }

​ 一直追下去,authenticate 方法又调用了 AbstractAuthenticatorauthenticate 方法。下面是该方法的实现。

AbstractAuthenticatorShiro 鉴权的顶级接口 Authenticator 的抽象实现类,ShiroAuthenticator 接口的注释中(只有下载了源码才会看见)给出了 6 种鉴权异常,可用于鉴权过程中出现错误抛出。

public final AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException {

        if (token == null) {
            throw new IllegalArgumentException("Method argument (authentication token) cannot be null.");
        }

        log.trace("Authentication attempt received for token [{}]", token);

        AuthenticationInfo info;
        try {
          // 进行身份验证的方法
            info = doAuthenticate(token);
            if (info == null) {
                String msg = "No account information found for authentication token [" + token + "] by this " +
                        "Authenticator instance.  Please check that it is configured correctly.";
                throw new AuthenticationException(msg);
            }
        } catch (Throwable t) {
        // Omit the more code
        }
}

​ 在进行身份验证时的 doAuthenticate(token) 方法是 AbstractAuthenticator 定义的抽象方法,由 ModularRealmAuthenticator 类实现,由此可见AbstractAuthenticator 采用了 模板方法模式 来进行身份的校验。

模板方法模式是类的行为模式。准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。这就是模板方法模式的用意。
比如定义一个操作中的算法的骨架,将步骤延迟到子类中。模板方法使得子类能够不去改变一个算法的结构即可重定义算法的某些特定步骤。
————————————————
版权声明:本文为CSDN博主「炸斯特」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/jason0539/article/details/45037535

​ 继续查看 doAuthenticate(AuthenticationToken authenticationToken)的实现代码:

protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
        assertRealmsConfigured();
        Collection<Realm> realms = getRealms();
        if (realms.size() == 1) {
            return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken);
        } else {
            return doMultiRealmAuthentication(realms, authenticationToken);
        }
    }

​ 可以看到,如果只有一个 Realm 就会调用 doSingleRealmAuthentication(Realm realm, AuthenticationToken token)

​ 如果有多个 Realm 就会调用 doMultiRealmAuthentication(Collection<Realm> realms, AuthenticationToken token)

​ 通过查看这两个方法的实现,发现无论哪个方法都会调用 Realm


AuthenticationInfo getAuthenticationInfo(AuthenticationToken token)

方法。 下面查看下 getAuthenticationInfo 方法的实现。
 public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
				// 先从缓存中获取
        AuthenticationInfo info = getCachedAuthenticationInfo(token);
   		// 如果缓存中没找到会从 Realm 的 doGetAuthenticationInfo 中获取
        if (info == null) {
            //otherwise not cached, perform the lookup:
            info = doGetAuthenticationInfo(token);
            log.debug("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", info);
            if (token != null && info != null) {
                cacheAuthenticationInfoIfPossible(token, info);
            }
        } else {
            log.debug("Using cached authentication info [{}] to perform credentials matching.", info);
        }

        if (info != null) {
            assertCredentialsMatch(token, info);
        } else {
            log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}].  Returning null.", token);
        }

        return info;
    }

​ 注意这一行代码:info = doGetAuthenticationInfo(token); 这个方法名是不是很熟悉??? 使用 IDEA command + 左键查看实现,红色框起来的就是我们自定义的 Realm

1

Ps: doAuthenticate(AuthenticationToken token) 方法也是采用的模板方法模式

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值