spring - Apache 四郎 : how to set the authenticationStrategy using spring applicationcontext?

标签 spring jakarta-ee web shiro realm

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

<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>

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

最佳答案

FirstSuccessfulStrategy 表示您的验证器将尝试您所有的 Realm 来验证用户,直到第一次成功为止。您的 Realm 按顺序配置:ldapRealmSaltedSha512JPARealm。因此,如果 lapRealm 将失败,验证器将尝试第二个。要解决这个问题,您可以尝试将最成功或最快的 Realm 配置为第一个,例如您可以将 Realm 顺序更改为 SaltedSha512JPARealmldapRealm:

<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

或者您可以尝试为该 Realm 使用不​​同的 token 类别。但只有当您对它们中的每一个都有不同的身份验证入口点时,它才会起作用。

UPD

似乎 ModularRealmAuthenticator 的设计使其始终尝试通过所有 Realm 对用户进行身份验证。 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;
}

关于spring - Apache 四郎 : how to set the authenticationStrategy using spring applicationcontext?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15705910/

相关文章:

java - 如何修复 Fortify 竞争条件 : Singleton Member Field issue

jakarta-ee - 为什么无状态 bean 被视为伪作用域并且不能具有循环依赖关系?

php - 将某个单元格从数据库发送到另一个 PHP 页面

web - Magento:设置刚刚创建的网站的配置值?

javascript - 捕获按键文档并开始在搜索框中输入

java - Spring 3 : disable SpEL evaluation of a bean property value?

java - 仅在某些记录上出现约束违规 spring JPA

spring - beanWrapperImpl 仅与 websphere 相关

jakarta-ee - TypedQuery 代替 JPA 中的普通查询

java - 在 Linux 中使用 Java 创建 MySql 备份