3

在基于 Spring 的 Web 应用程序中,我一直在努力使用 shiro 1.2.1 进行 authenticationStrategy 设置。我有2个领域。一个针对 ldap 进行身份验证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>

有什么我做得不好的吗?

4

2 回答 2

2

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会失败,authenticator 会尝试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;
}
于 2013-03-30T12:59:31.323 回答
0
<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"/>

然后它将按预期工作

于 2015-01-30T12:35:04.697 回答