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】:<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"/>
然后它会按预期工作
【讨论】:
【参考方案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
会失败,验证器会尝试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 人员和管理人员来说效果很好。以上是关于apache shiro:如何使用 spring applicationcontext 设置 authenticationStrategy?的主要内容,如果未能解决你的问题,请参考以下文章
将 Struts 2 与 Apache Shiro 集成时如何显示结果页面
在Spring MVC中使用Apache Shiro安全框架