shiro多realm认证学习实现

突然接到了一个需求,一个系统需要实现多种认证登录。
之前都是修改shiro的realm,根据不同情况去判断,会造成代码特别臃肿。
所以这次尝试用多个realm 来实现多种认证方式登录。
认证之前先了解了一下shiro多realm处理的三种策略:

SecurityManager 接口继承了 Authenticator,另外还有一个 ModularRealmAuthenticator 实现,其委托给多个 Realm 进行验证,验证规则通过 AuthenticationStrategy 接口指定,默认提供的实现:

  • FirstSuccessfulStrategy:只要有一个 Realm 验证成功即可,只返回第一个 Realm 身份验证成功的认证信息,其他的忽略;
  • AtLeastOneSuccessfulStrategy:只要有一个 Realm 验证成功即可,和 FirstSuccessfulStrategy不同,返回所有 Realm 身份验证成功的认证信息;
  • AllSuccessfulStrategy:所有 Realm 验证成功才算成功,且返回所有 Realm 身份验证成功的认证信息,如果有一个失败就失败了。
    ModularRealmAuthenticator 默认使用 AtLeastOneSuccessfulStrategy 策略。

首先配置多个realm认证和认证的处理策略,这里采用默认处理策略:

<!-- 定义 Shiro 主要业务对象 -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<!-- 多Realm配置,和处理策略 -->
		<property name="authenticator">
			<bean class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">
				<property name="authenticationStrategy">
					<!-- 至少有一个Realm认证通过 -->
					<bean class="org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy"/>
				</property>
			</bean>
		</property>
		<property name="realms">
			<list>
				<ref bean="systemRealm"/>
				<ref bean="testLoginRealm"/>
				<ref bean="keyLoginRealm"/>
			</list>
		</property>
		<property name="subjectFactory" ref="casSubjectFactory"/>
		<property name="sessionManager" ref="sessionManager"/>
		<property name="cacheManager" ref="cacheManagerShiro"/>
	</bean>

多realm认证调用流程,采用默认AtLeastOneSuccessfulStrategy 策略

	protected AuthenticationInfo doMultiRealmAuthentication(Collection<Realm> realms, AuthenticationToken token) {
        AuthenticationStrategy strategy = getAuthenticationStrategy();
        //在所有Reaml之前使用
        AuthenticationInfo aggregate = strategy.beforeAllAttempts(realms, token);
        if (log.isTraceEnabled()) {
            log.trace("Iterating through {} realms for PAM authentication", realms.size());
        }
        for (Realm realm : realms) {
        	//在每个Reaml前使用
            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);
                    }
                }
                //在每个Reaml后使用
                aggregate = strategy.afterAttempt(realm, token, info, aggregate, t);
            } else {
                log.debug("Realm [{}] does not support token {}.  Skipping realm.", realm, token);
            }
        }
        //在所有Reaml之后使用
        aggregate = strategy.afterAllAttempts(token, aggregate);
        return aggregate;
    }

可以通过自己继承AbstractAuthenticationStrategy抽象类来实现:beforeAllAttempts、beforeAttempt、afterAttempt、afterAllAttempts来实现自定义策略。
实现多realm处理策略

笔记:

当多个realm认证成功,AtLeastOneSuccessfulStrategy策略会返回多个principal,
当调用subject.getPrincipal(),实际会获取principals中的第一个。
如果系统中不处理多个principal 情况,采用FirstSuccessfulStrategy和AtLeastOneSuccessfulStrategy策略登录结果相同

	//调用代码
	Subject subject = getSubject(request, response);
	Session session = subject.getSession();
	subject.getPrincipal()
	//实际会获取principals中的第一个
	//org.apache.shiro.subject.support.DelegatingSubject.java
	public Object getPrincipal() {
	    return getPrimaryPrincipal(getPrincipals());
	}
    private Object getPrimaryPrincipal(PrincipalCollection principals) {
        if (!CollectionUtils.isEmpty(principals)) {
            return principals.getPrimaryPrincipal();
        }
        return null;
    }
    //org.apache.shiro.subject.SimplePrincipalCollection.java
    public Object getPrimaryPrincipal() {
        if (isEmpty()) {
            return null;
        }
        return iterator().next();
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值