ljj481322 2020-11-01 10:56 采纳率: 0%
浏览 59

shiro 多个Realm时同时设置了AuthenticationStrategy,第一个成功后如何中止后边的Realm认证

举个例子:
移动端有用户名密码、手机验证码、邮箱验证码与人脸识别等各种登陆方式。
自定义4个Realm时,需要设置认证策略(也可以认为是Realm的执行顺序)。

ModularRealmAuthenticator的AuthenticationStrategy的策略为
1. AtLeastOneSuccessfulStrategy :如果一个(或更多)Realm 验证成功,则整体的尝试被认为是成功的。如果没有一个验证成功,则整体尝试失败。

  1. FirstSuccessfulStrategy 只有第一个成功地验证的Realm 返回的信息将被使用。后面的realm会被忽略,如果一个都没有成功则失败。

  2. AllSucessfulStrategy 为了整体的尝试成功,所有配置的Realm 必须验证成功。如果没有一个验证成功,则整体尝试失败。

ModularRealmAuthenticator 默认的是AtLeastOneSuccessfulStrategy

查看shiro-core-1.6.0的源码

protected AuthenticationInfo doMultiRealmAuthentication(Collection<Realm> realms, AuthenticationToken token)
  {
    AuthenticationStrategy strategy = getAuthenticationStrategy();

    AuthenticationInfo aggregate = strategy.beforeAllAttempts(realms, token);

    if (log.isTraceEnabled()) {
      log.trace("Iterating through {} realms for PAM authentication", Integer.valueOf(realms.size()));
    }

    for (Iterator localIterator = realms.iterator(); localIterator.hasNext(); ) { Realm realm = (Realm)localIterator.next();
      try
      {
        aggregate = strategy.beforeAttempt(realm, token, aggregate);
      }
      catch (ShortCircuitIterationException shortCircuitSignal)
      {
        break label231:
      }

      if (realm.supports(token))
      {
        log.trace("Attempting to authenticate token [{}] using realm [{}]", token, realm);

        AuthenticationInfo info = null;
        Throwable t = null;
        try {
          info = realm.getAuthenticationInfo(token);
        } catch (Throwable throwable) {
          t = throwable;
          if (log.isDebugEnabled()) {
            String msg = "Realm [" + realm + "] threw an exception during a multi-realm authentication attempt:";
            log.debug(msg, t);
          }
        }

        aggregate = strategy.afterAttempt(realm, token, info, aggregate, t);
      }
      else {
        log.debug("Realm [{}] does not support token {}.  Skipping realm.", realm, token);
      }
    }

    label231: aggregate = strategy.afterAllAttempts(token, aggregate);

    return aggregate;
  }


如上代码中有两种返回:
一种是异常,另外一种是 if (realm.supports(token))中的正常执行。
shirocofing中的设置


  public AbstractAuthenticator abstractAuthenticator(UserRealm userRealm, PhoneAndVerificationCodeShiroRealm phoneShiroRealm){
        // 自定义模块化认证器,用于解决多realm抛出异常问题
        //开始没用自定义异常问题,发现不管是账号密码错误还是什么错误
        //shiro只会抛出一个AuthenticationException异常
        ModularRealmAuthenticator  authenticator = new ModularRealmAuthenticator ();
        // 认证策略:AtLeastOneSuccessfulStrategy(默认),AllSuccessfulStrategy,FirstSuccessfulStrategy
        authenticator.setAuthenticationStrategy(new FirstSuccessfulStrategy());
        // 加入realms
        List<Realm> realms = new ArrayList<>(); 
        realms.add(phoneShiroRealm);
        realms.add(userRealm);
        authenticator.setRealms(realms);
        return authenticator;

    }

if(realm.supports(token)) 会生效。所以不管定义多少个Realm,这里只会执行一个Realm。
** 但是 我这边phoneShiroRealm认证成功后还是会执行userRealm。
请问各位大神 如何做到第一个认证成功后不在执行后边的Realm。因为后边的Realm在参数不足的情况下会认证失败,且会把认证失败的信息记录至数据库。看着就不好。**

  • 写回答

1条回答 默认 最新

  • XinHaiYe 2023-06-10 19:35
    关注

    在 Shiro 中,当多个 Realm 配置时,如果第一个 Realm 认证成功,后面的 Realm 将不会再进行认证。这是因为在 Shiro 中,认证策略默认为 FirstSuccessfulStrategy,即第一个 Realm 认证成功即可。

    如果你需要自定义认证策略,可以通过实现 AuthenticationStrategy 接口来实现。在自定义的 AuthenticationStrategy 实现类中,你可以根据自己的需求来决定是否中止后面的 Realm 认证。

    例如,如果你希望只有在第一个 Realm 认证失败时才进行后面的 Realm 认证,可以实现一个类似于下面的代码:

    public class CustomAuthenticationStrategy extends FirstSuccessfulStrategy {
    
        @Override
        public AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo singleRealmInfo, AuthenticationInfo aggregateInfo, Throwable t) throws AuthenticationException {
            AuthenticationInfo info = super.afterAttempt(realm, token, singleRealmInfo, aggregateInfo, t);
            if (info == null && t != null) {
                // 如果第一个 Realm 认证失败,且出现了异常,则继续进行后面的 Realm 认证
                throw t;
            }
            return info;
        }
    }
    

    然后在 Shiro 配置文件中将认证策略设置为自定义的策略即可:

    [main]
    customAuthStrategy = com.example.CustomAuthenticationStrategy
    
    myRealm1 = ...
    myRealm2 = ...
    
    securityManager.realms = $myRealm1, $myRealm2
    securityManager.authenticator.authenticationStrategy = $customAuthStrategy
    
    评论

报告相同问题?

悬赏问题

  • ¥60 求一个简单的网页(标签-安全|关键词-上传)
  • ¥35 lstm时间序列共享单车预测,loss值优化,参数优化算法
  • ¥15 基于卷积神经网络的声纹识别
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 CSAPPattacklab
  • ¥15 一直显示正在等待HID—ISP