apache shiro:如何使用 spring applicationcontext 设置 authenticationStrategy?

Posted

技术标签:

【中文标题】apache shiro:如何使用 spring applicationcontext 设置 authenticationStrategy?【英文标题】:apache shiro: how to set the authenticationStrategy using spring applicationcontext? 【发布时间】: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>

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

【问题讨论】:

【参考方案1】:

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

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

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

然后它会按预期工作

【讨论】:

以上是关于apache shiro:如何使用 spring applicationcontext 设置 authenticationStrategy?的主要内容,如果未能解决你的问题,请参考以下文章

Spring 上的 Apache Shiro 会话管理

将 Struts 2 与 Apache Shiro 集成时如何显示结果页面

在Spring MVC中使用Apache Shiro安全框架

Apache Shiro Web应用整合-配置

Apache Shiro 与 Spring Security

Apache shiro的简单介绍与使用(与spring整合使用)