32、shiro 框架入门三

1、AuthenticationStrategy实现

//在所有Realm验证之前调用
AuthenticationInfo beforeAllAttempts(
Collection<? extends Realm> realms, AuthenticationToken token)
throws AuthenticationException;
//在每个Realm之前调用
AuthenticationInfo beforeAttempt(
Realm realm, AuthenticationToken token, AuthenticationInfo aggregate)
throws AuthenticationException;
//在每个Realm之后调用
AuthenticationInfo afterAttempt(
Realm realm, AuthenticationToken token,
AuthenticationInfo singleRealmInfo, AuthenticationInfo aggregateInfo, Throwable t)
throws AuthenticationException;
//在所有Realm之后调用
AuthenticationInfo afterAllAttempts(
AuthenticationToken token, AuthenticationInfo aggregate)
throws AuthenticationException;

因为每个AuthenticationStrategy实例都是无状态的,所有每次都通过接口将相应的认证信息传入下一次流程;通过如上接口可以进行如合并/返回第一个验证成功的认证信息。

  自定义实现时一般继承org.apache.shiro.authc.pam.AbstractAuthenticationStrategy

下边这个OnlyOneAuthenticatorStrategy只允许一个成功的验证信息,进行返回,否则会报AuthenticationException,只返回第一个验证成功的Realm的认证信息

public class OnlyOneAuthenticatorStrategy extends AbstractAuthenticationStrategy {

    @Override
public AuthenticationInfo beforeAllAttempts(Collection<? extends Realm> realms, AuthenticationToken token) throws AuthenticationException {
return new SimpleAuthenticationInfo();//返回一个权限的认证信息,在进行验证之前返回的信息,不对权限信息进行处理
} @Override
public AuthenticationInfo beforeAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo aggregate) throws AuthenticationException {
return aggregate;//返回之前合并的,在进行验证之前返回的信息,不对权限信息进行处理
  }
  @Override
  public AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo singleRealmInfo, AuthenticationInfo aggregateInfo, Throwable t) throws AuthenticationException {
     AuthenticationInfo info;
     if (singleRealmInfo == null)
     {
       info = aggregateInfo;
     } else
    {
       if (aggregateInfo == null) {
       info = singleRealmInfo;
     } else {
       info = merge(singleRealmInfo, aggregateInfo);
       if(info.getPrincipals().getRealmNames().size() > 1)
       {
         System.out.println(info.getPrincipals().getRealmNames());
         throw new AuthenticationException("Authentication token of type [" + token.getClass() + "] " +
        "could not be authenticated by any configured realms. Please ensure that only one realm can " +
         "authenticate these tokens.");
       }
     }
   }
     return info;
}
@Override
public AuthenticationInfo afterAllAttempts(AuthenticationToken token, AuthenticationInfo aggregate) throws AuthenticationException
{
    return aggregate;
} }

这里的shiro主要就是将多个AuthenticationToken信息合并在一起,

2、AbstractAuthenticationStrategy中的merge方法,主要就是先检查该

AuthenticationInfo 是不是可以merge的类型,如果是则将其转换为可以merge的类型,然后调用merge方法
/**
* Merges the specified <code>info</code> argument into the <code>aggregate</code> argument and then returns an
* aggregate for continued use throughout the login process.
* <p/>
* This implementation merely checks to see if the specified <code>aggregate</code> argument is an instance of
* {@link org.apache.shiro.authc.MergableAuthenticationInfo MergableAuthenticationInfo}, and if so, calls
* <code>aggregate.merge(info)</code> If it is <em>not</em> an instance of
* <code>MergableAuthenticationInfo</code>, an {@link IllegalArgumentException IllegalArgumentException} is thrown.
* Can be overridden by subclasses for custom merging behavior if implementing the
* {@link org.apache.shiro.authc.MergableAuthenticationInfo MergableAuthenticationInfo} is not desired for some reason.
*/
protected AuthenticationInfo merge(AuthenticationInfo info, AuthenticationInfo aggregate) {
if( aggregate instanceof MergableAuthenticationInfo ) {
((MergableAuthenticationInfo)aggregate).merge(info);
return aggregate;
} else {
throw new IllegalArgumentException( "Attempt to merge authentication info from multiple realms, but aggregate " +
"AuthenticationInfo is not of type MergableAuthenticationInfo." );
}
}

可以进行多个AuthenticationInfo信息进行merge的功能如下所示,返回所有验证成功的Realm的认证信息

public class AtLeastTwoAuthenticatorStrategy extends AbstractAuthenticationStrategy {

    @Override
public AuthenticationInfo beforeAllAttempts(Collection<? extends Realm> realms, AuthenticationToken token) throws AuthenticationException {
return new SimpleAuthenticationInfo();//返回一个权限的认证信息
} @Override
public AuthenticationInfo beforeAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo aggregate) throws AuthenticationException {
return aggregate;//返回之前合并的
} @Override
public AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo singleRealmInfo, AuthenticationInfo aggregateInfo, Throwable t) throws AuthenticationException {
AuthenticationInfo info;
if (singleRealmInfo == null) {
info = aggregateInfo;
} else {
if (aggregateInfo == null) {
info = singleRealmInfo;
} else {
info = merge(singleRealmInfo, aggregateInfo);
}
} return info;
} @Override
public AuthenticationInfo afterAllAttempts(AuthenticationToken token, AuthenticationInfo aggregate) throws AuthenticationException {
if (aggregate == null || CollectionUtils.isEmpty(aggregate.getPrincipals()) || aggregate.getPrincipals().getRealmNames().size() < 2) {
throw new AuthenticationException("Authentication token of type [" + token.getClass() + "] " +
"could not be authenticated by any configured realms. Please ensure that at least two realm can " +
"authenticate these tokens.");
} return aggregate;
}

3、对于Subject线程进行解绑

@After
public void tearDown() throws Exception {
ThreadContext.unbindSubject();//退出时请解除绑定Subject到线程 否则对下次测试造成影响
}
上一篇:Java程序猿JavaScript学习笔记(14——扩大jQuery UI)


下一篇:后记:Cookie安全大辩论总结