一、AuthenticationStrategy 是个无状态的组件,在认证过程中会进行如下4次调用
1.在所有Realm被调用之前
2.在调用Realm的getAuthenticationInfo方法之前
3.在调用Realm的getAuthenticationInfo 方法之后
4.在所有Realm被调用之后 即实现AuthenticationStrategy接口的类都要实现以下四个方法:beforeAllAttempts,beforeAttempt,afterAttempt,afterAllAttempts
二、对于多realm配置,Shiro有3中认证策略的具体实现
AtLeastOneSuccessfulStrategy(默认):只要有一个Realm验证成功即可,和FirstSuccessfulStrategy不同,返回所有Realm身份验证成功的认证信息;
FirstSuccessfulStrategy:只要有一个Realm验证成功即可,只返回第一个Realm身份验证成功的认证信息,其他的忽略;
AllSuccessfulStrategy:所有Realm验证成功才算成功,且返回所有Realm身份验证成功的认证信息,如果有一个失败就失败了。
三测试用例
1.ini配置
[main]
#指定securityManager的authenticator实现
authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator
securityManager.authenticator=$authenticator
#指定securityManager.authenticator的authenticationStrategy
allSuccessfulStrategy=org.apache.shiro.authc.pam.AllSuccessfulStrategy
securityManager.authenticator.authenticationStrategy=$allSuccessfulStrategy
myRealm1=com.github.zhangkaitao.shiro.chapter2.realm.MyRealm1
myRealm3=com.github.zhangkaitao.shiro.chapter2.realm.MyRealm3
securityManager.realms=$myRealm1,$myRealm3
2.Realm定义
public class MyRealm1 implements Realm
{
@Override
public String getName()
{
return "myrealm1";
}
@Override
public boolean supports(AuthenticationToken token)
{
return token instanceof UsernamePasswordToken; //仅支持UsernamePasswordToken类型的Token
}
@Override
public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException
{
String username = (String)token.getPrincipal(); //得到用户名
String password = new String((char[])token.getCredentials()); //得到密码
if(!"zhang".equals(username))
{
throw new UnknownAccountException(); //如果用户名错误
}
if(!"123".equals(password))
{
throw new IncorrectCredentialsException(); //如果密码错误
}
//如果身份认证验证成功,返回一个AuthenticationInfo实现;
return new SimpleAuthenticationInfo(username, password, getName());
}
}
public class MyRealm3 implements Realm
{
@Override
public String getName()
{
return "myrealm3";
}
@Override
public boolean supports(AuthenticationToken token)
{
return token instanceof UsernamePasswordToken; //仅支持UsernamePasswordToken类型的Token
}
@Override
public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException
{
String username = (String)token.getPrincipal(); //得到用户名
String password = new String((char[])token.getCredentials()); //得到密码
if(!"zhang".equals(username))
{
throw new UnknownAccountException(); //如果用户名错误
}
if(!"123".equals(password))
{
throw new IncorrectCredentialsException(); //如果密码错误
}
//如果身份认证验证成功,返回一个AuthenticationInfo实现;
return new SimpleAuthenticationInfo(username + "@163.com", password, getName());
}
}
public class MyRealm4 implements Realm
{
@Override
public String getName()
{
return "myrealm4";
}
@Override
public boolean supports(AuthenticationToken token)
{
return token instanceof UsernamePasswordToken; //仅支持UsernamePasswordToken类型的Token
}
@Override
public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException
{
String username = (String)token.getPrincipal(); //得到用户名
String password = new String((char[])token.getCredentials()); //得到密码
if(!"zhang".equals(username))
{
throw new UnknownAccountException(); //如果用户名错误
}
if(!"123".equals(password))
{
throw new IncorrectCredentialsException(); //如果密码错误
}
//如果身份认证验证成功,返回一个AuthenticationInfo实现;
return new SimpleAuthenticationInfo(username, password, getName());
}
}
3.登录逻辑
private void login(String configFile)
{
//1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager
Factory<org.apache.shiro.mgt.SecurityManager> factory =
new IniSecurityManagerFactory(configFile);
//2、得到SecurityManager实例 并绑定给SecurityUtils
org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
//3、得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");
subject.login(token);
}
4.测试AllSuccessfulStrategy成功:
@Test
public void testAllSuccessfulStrategyWithSuccess() {
login("classpath:shiro-authenticator-all-success.ini");
Subject subject = SecurityUtils.getSubject();
//得到一个身份集合,其包含了Realm验证成功的身份信息
PrincipalCollection principalCollection = subject.getPrincipals();
Assert.assertEquals(2, principalCollection.asList().size());
}
总结:PrincipalCollection principalCollection = subject.getPrincipals(); 因为myRealm1和myRealm4返回的身份一样所以输出时只返回一个,所以得到一个身份集合