赞
踩
在流程图3中,有Authenticator和AuthenticationStrategy2个接口。
Authenticator的职责是验证用户帐号,是Shiro API中身份验证核心的入口点:
它只有一个方法:
- public AuthenticationInfo authenticate(AuthenticationToken authenticationToken)
- throws AuthenticationException;
选中AuthenticationInfo,按住Ctrl+t,可以看到它的继承体系。
SecurityManager接口继承了Authenticator,另外还有一个ModularRealmAuthenticator实现,其委托给多个Realm进行验证,验证规则通过AuthenticationStrategy接口指定,默认提供的实现:
FirstSuccessfulStrategy:只要有一个Realm验证成功即可,只返回第一个Realm身份验证成功的认证信息,其他的忽略;
AtLeastOneSuccessfulStrategy:只要有一个Realm验证成功即可,和FirstSuccessfulStrategy不同,返回所有Realm身份验证成功的认证信息;
AllSuccessfulStrategy:所有Realm验证成功才算成功,且返回所有Realm身份验证成功的认证信息,如果有一个失败就失败了。
ModularRealmAuthenticator默认使用AtLeastOneSuccessfulStrategy策略。
一个例子:
假设我们有三个realm:
myRealm1: 用户名/密码为zhang/123时成功,且返回身份/凭据为zhang/123;
myRealm2: 用户名/密码为wang/123时成功,且返回身份/凭据为wang/123;
myRealm3: 用户名/密码为zhang/123时成功,且返回身份/凭据为zhang@163.com/123,和myRealm1不同的是返回时的身份变了;
三个reaml文件如下:
package com.lgy.shiro; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.realm.Realm; public class MyRealm1 implements Realm { public String getName() { return "myrealm1"; } public boolean supports(AuthenticationToken token) { return token instanceof UsernamePasswordToken; //仅支持UsernamePasswordToken类型的Token } 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()); } } package com.lgy.shiro; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.realm.Realm; public class MyRealm2 implements Realm { public String getName() { return "myrealm2"; } public boolean supports(AuthenticationToken token) { return token instanceof UsernamePasswordToken; //仅支持UsernamePasswordToken类型的Token } public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String username = (String)token.getPrincipal(); //得到用户名 String password = new String((char[])token.getCredentials()); //得到密码 if(!"wang".equals(username)) { throw new UnknownAccountException(); //如果用户名错误 } if(!"123".equals(password)) { throw new IncorrectCredentialsException(); //如果密码错误 } //如果身份认证验证成功,返回一个AuthenticationInfo实现; return new SimpleAuthenticationInfo(username, password, getName()); } } package com.lgy.shiro; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.realm.Realm; public class MyRealm3 implements Realm { public String getName() { return "myrealm3"; } public boolean supports(AuthenticationToken token) { return token instanceof UsernamePasswordToken; //仅支持UsernamePasswordToken类型的Token } 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@qq.com", password, getName()); } }
- 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);
- }
-
- @After
- public void tearDown() throws Exception {
- ThreadContext.unbindSubject();//退出时请解除绑定Subject到线程 否则对下次测试造成影响
- }
上面说的:
默认策越(ModularRealmAuthenticator默认使用AtLeastOneSuccessfulStrategy策略。)DEMO
ini文件:
- [main]
-
- #声明一个realm
-
- myRealm1=com.lgy.shiro.MyRealm1
- myRealm2=com.lgy.shiro.MyRealm2
- myRealm3=com.lgy.shiro.MyRealm3
- #指定securityManager的realms实现
-
- securityManager.realms=$myRealm1,$myRealm2,$myRealm3
- @Test
- public void testStrategyWithdefault() {
-
-
- login("classpath:shiro-auth-default.ini");
- // login("classpath:shiro-realm.ini");
- Subject subject = SecurityUtils.getSubject();
- /*
- boolean b = subject.isAuthenticated();
- System.out.println(b);*/
- //得到一个身份集合,其包含了Realm验证成功的身份信息
- PrincipalCollection principalCollection = subject.getPrincipals();
- System.out.println(principalCollection.asList().size()); //返回所有的身份凭证信息
- //Assert.assertEquals(2, principalCollection.asList().size());
- }
FirstSuccessfulStrategy策越,demo如下:
ini文件:
[main] #指定securityManager的authenticator实现 authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator securityManager.authenticator=$authenticator #指定securityManager.authenticator的authenticationStrategy firstSuccessfulStrategy=org.apache.shiro.authc.pam.FirstSuccessfulStrategy securityManager.authenticator.authenticationStrategy=$firstSuccessfulStrategy #声明一个realm myRealm1=com.lgy.shiro.MyRealm1 myRealm2=com.lgy.shiro.MyRealm2 myRealm3=com.lgy.shiro.MyRealm3 #指定securityManager的realms实现 securityManager.realms=$myRealm1,$myRealm2,$myRealm3
- @Test
- public void testStrategyWithdefirst() {
- login("classpath:shiro-auth-first.ini");
- Subject subject = SecurityUtils.getSubject();
- System.out.println(subject.isAuthenticated());
-
- PrincipalCollection principalCollection = subject.getPrincipals();
- System.out.println(principalCollection.asList().size());
- }
验证信息是zhang/123, myRealm1和myRealm2是能通过的,打印返回的size为1,正如前面所说的只要有一个Realm验证成功即可,只返回第一个Realm身份验证成功的认证信息,其他的忽略;
AllSuccessfulStrategy测试,demo如下:
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 #声明一个realm myRealm1=com.lgy.shiro.MyRealm1 myRealm2=com.lgy.shiro.MyRealm2 myRealm3=com.lgy.shiro.MyRealm3 #指定securityManager的realms实现 securityManager.realms=$myRealm1,$myRealm2,$myRealm3
测试文件:
- @Test
- public void testStrategyWithdeAll() {
- login("classpath:shiro-auth-all.ini");
- Subject subject = SecurityUtils.getSubject();
- System.out.println(subject.isAuthenticated());
-
- PrincipalCollection principalCollection = subject.getPrincipals();
- System.out.println(principalCollection.asList().size());
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。