【问题标题】:apache shiro: how to set the authenticationStrategy using spring applicationcontext?apache shiro:如何使用 spring applicationcontext 设置 authenticationStrategy?
【发布时间】:2013-03-20 07:29:09
【问题描述】:

我一直在努力在基于 Spring 的 Web 应用程序中使用 shiro 1.2.1 进行 authenticationStrategy 设置。我有2个领域。一种针对database 进行身份验证,另一种针对ldap 进行身份验证。两个realms 工作正常,只是我想要一个FirstSuccessfulStrategy,但似乎两个领域仍在被调用。这是我的安全应用程序上下文:

<bean id="passwordService" class="org.apache.shiro.authc.credential.DefaultPasswordService">
    <property name="hashService" ref="hashService" />

</bean>

<bean id="hashService" class="org.apache.shiro.crypto.hash.DefaultHashService">
    <property name="hashAlgorithmName" value="SHA-512" />
    <property name="hashIterations" value="500000" />
</bean>


<bean id="SaltedSha512JPARealm" class="bla.bla.webapp.security.SaltedSha512JPARealm">
    <property name="credentialsMatcher">
        <bean class="org.apache.shiro.authc.credential.PasswordMatcher">
            <property name="passwordService" ref="passwordService"/>
        </bean>
    </property>

</bean>


<bean id="ldapContextFactory" class="org.apache.shiro.realm.ldap.JndiLdapContextFactory">
    <property name="url" value="${user.ldap.connection.url}"/>
    <property name="authenticationMechanism" value="${user.ldap.connection.auth_mecanism}"/>
</bean>

<bean id="ldapRealm" class="bla.bla.webapp.security.LDAPRealm">
    <property name="userDnTemplate" value="${user.ldap.connection.userDnTemplate}"/>
    <property name="contextFactory" ref="ldapContextFactory" />

</bean>

<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" depends-on="roleRepository,roleRightRepository,rightRepository,userRepository">

    <property name="realms">
        <list>
            <ref local="ldapRealm"/>
            <ref local="SaltedSha512JPARealm"/>
        </list>
    </property>
    <property name="authenticator.authenticationStrategy">
        <bean class="org.apache.shiro.authc.pam.FirstSuccessfulStrategy"/>
    </property>

</bean>

有什么我做得不好的地方吗?

【问题讨论】:

    标签: spring jakarta-ee web shiro realm


    【解决方案1】:

    FirstSuccessfulStrategy 表示您的身份验证器将尝试您的所有领域来对用户进行身份验证,直到第一次成功。您的领域已按顺序配置:ldapRealm、SaltedSha512JPARealm。因此,如果lapRealm 失败,验证器将尝试第二个。要解决这个问题,您可以尝试将最成功或最快的领域配置为第一,例如您可以将您的领域顺序更改为SaltedSha512JPARealm、ldapRealm:

    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" depends-on="roleRepository,roleRightRepository,rightRepository,userRepository">
    
        <property name="realms">
            <list>
                <ref local="SaltedSha512JPARealm"/>
                <ref local="ldapRealm"/>
            </list>
        </property>
        <property name="authenticator.authenticationStrategy">
            <bean class="org.apache.shiro.authc.pam.FirstSuccessfulStrategy"/>
        </property>
    
    </bean>
    

    但是你应该明白,对于这个配置,如果SaltedSha512JPARealm会失败,验证器会尝试ldapRealm。

    或者您可以尝试为该领域使用不​​同的令牌类。但它只有在您对它们每个都有不同的身份验证入口点时才有效。

    UPD

    似乎ModularRealmAuthenticator 的设计使其始终尝试通过所有领域对用户进行身份验证。 FirstSuccessfulStrategy 只能影响认证结果。它将首先返回成功的AuthenticationInfo。要实现您的目标,您需要覆盖 ModularRealmAuthenticator#doMultiRealmAuthentication 方法。它可能看起来像这样:

    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", realms.size());
        }
        for (Realm realm : realms) {
            aggregate = strategy.beforeAttempt(realm, token, aggregate);
            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);
                // dirty dirty hack
                if (aggregate != null && !CollectionUtils.isEmpty(aggregate.getPrincipals())) {
                    return aggregate;
                }
                // end dirty dirty hack
            } else {
                log.debug("Realm [{}] does not support token {}.  Skipping realm.", realm, token);
            }
        }
        aggregate = strategy.afterAllAttempts(token, aggregate);
        return aggregate;
    }
    

    【讨论】:

    • 感谢您的回答。我的问题是,即使对 stuart ldap server(blog.stuartlewis.com/2008/07/07/test-ldap-service) 成功进行身份验证后,它也会尝试使用 SaltedSha512JPARealm 对数据库进行身份验证。这就是为什么我的配置有问题。知道首先添加了 ldapRealm 它不应该发生吗?
    • 你是对的。似乎ModularRealmAuthenticator 的设计使其始终尝试通过所有领域对用户进行身份验证。刚刚更新了答案。
    • 您好,很抱歉回复晚了。我已经尝试使用不同的令牌并根据我放在 UI 上的组合框创建它们,就像 MS windows 登录切换域一样。这是我现在的快速修复。我将在下一次迭代中尝试这个解决方案,我被最后期限抓住了。这样修复对 UI 人员和管理人员来说效果很好。
    【解决方案2】:
    <property name="authenticator.authenticationStrategy">
        <bean class="org.apache.shiro.authc.pam.FirstSuccessfulStrategy"/>
    </property>
    

    上面的定义是错误的。定义如下

    <property name="authenticator.authenticationStrategy" ref="authcStrategy"/>
    

    并分别定义下面的bean定义

    <bean id="authcStrategy"     class="org.apache.shiro.authc.pam.FirstSuccessfulStrategy"/>
    

    然后它会按预期工作

    【讨论】:

      猜你喜欢
      • 2012-07-24
      • 2012-01-12
      • 2015-03-05
      • 2014-08-31
      • 2014-10-04
      • 2017-09-28
      • 1970-01-01
      • 2018-03-15
      相关资源
      最近更新 更多