(四)自定义多个Realm以及Authenticator与AuthenticationStrategy
-
多Realm配置
#声明一个realm myRealm1=com.github.zhangkaitao.shiro.chapter2.realm.MyRealm1 myRealm2=com.github.zhangkaitao.shiro.chapter2.realm.MyRealm2 #指定securityManager的realms实现 securityManager.realms=$myRealm1,$myRealm2
- securityManager会按照realms指定的顺序进行身份认证。此处我们使用显示指定顺序的方式指定了Realm的顺序,如果删除“securityManager.realms=$myRealm1,$myRealm2”,那么securityManager会按照realm声明的顺序进行使用(即无需设置realms属性,其会自动发现),当我们显示指定realm后,其他没有指定realm将被忽略,如“securityManager.realms=$myRealm1”,那么myRealm2不会被自动设置进去
-
1、变量名=全限定类名会自动创建一个类实例
2、变量名.属性=值 自动调用相应的setter方法进行赋值
3、$变量名 引用之前的一个对象实例
-
Authenticator及AuthenticationStrategy
- Authenticator的职责是验证用户帐号,是Shiro API中身份验证核心的入口点:
public AuthenticationInfo authenticate(AuthenticationToken authenticationToken) throws AuthenticationException;
- SecurityManager接口继承了Authenticator,另外还有一个ModularRealmAuthenticator实现(ModularRealmAuthenticator默认使用AtLeastOneSuccessfulStrategy策略。),其委托给多个Realm进行验证,验证规则通过AuthenticationStrategy接口指定,默认提供的实现:
- FirstSuccessfulStrategy:只要有一个Realm验证成功即可,只返回第一个Realm身份验证成功的认证信息,其他的忽略;
- AtLeastOneSuccessfulStrategy:只要有一个Realm验证成功即可,和FirstSuccessfulStrategy不同,返回所有Realm身份验证成功的认证信息;
- AllSuccessfulStrategy:所有Realm验证成功才算成功,且返回所有Realm身份验证成功的认证信息,如果有一个失败就失败了。
一、案例
- 需求:
假设我们有三个realm:
myRealm1: 用户名/密码为zhang/123时成功,且返回身份/凭据为zhang/123;
myRealm2: 用户名/密码为wang/123时成功,且返回身份/凭据为wang/123;
myRealm3: 用户名/密码为zhang/123时成功,且返回身份/凭据为zhang@163.com/123,和myRealm1不同的是返回时的身份变了;
- pom.xml依赖省略,可查看前几章
- 配置shiro.ini文件
[main]
#指定securityManager的authenticator实现 authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator securityManager.authenticator=$authenticator
#指定securityManager.authenticator的authenticationStrategy allSuccessfulStrategy=org.apache.shiro.authc.pam.FirstSuccessfulStrategy securityManager.authenticator.authenticationStrategy=$allSuccessfulStrategy
myRealm1=realms.MyRealm1 myRealm2=realms.MyRealm2 myRealm3=realms.MyRealm3 securityManager.realms=$myRealm1,$myRealm2,$myRealm3 [users] zhang=123 wang=123
-
- 认证策略为FirstSuccessfulStrategy ,只要有一个Realm验证成功即可,只返回第一个Realm身份验证成功的认证信息,其他的忽略
- MyRealm1.java
package realms; 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.SimpleAccount; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; public class MyRealm1 extends AuthorizingRealm{ /** * 判断授权的 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // TODO Auto-generated method stub return null; } /** * 判断认证的 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String userName=token.getPrincipal().toString(); String passWord=new String((char[])token.getCredentials()); if(!userName.equals("zhang")) throw new UnknownAccountException("Realm1 用户名错误"); if(!passWord.equals("123")) throw new IncorrectCredentialsException("Realm1 密码错误"); return new SimpleAccount(userName, passWord, getName()); } }
- MyRealm2.java
package realms; 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.SimpleAccount; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; public class MyRealm2 extends AuthorizingRealm{ /** * 判断授权的 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // TODO Auto-generated method stub return null; } /** * 判断认证的 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String userName=token.getPrincipal().toString(); String passWord=new String((char[])token.getCredentials()); if(!userName.equals("wang")) throw new UnknownAccountException("Realm2 用户名错误"); if(!passWord.equals("123")) throw new IncorrectCredentialsException("Realm2 密码错误"); return new SimpleAccount(userName, passWord, getName()); } }
- MyRealm3.java
package realms; 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.SimpleAccount; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; public class MyRealm3 extends AuthorizingRealm{ /** * 判断授权的 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // TODO Auto-generated method stub return null; } /** * 判断认证的 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String userName=token.getPrincipal().toString(); String passWord=new String((char[])token.getCredentials()); if(!userName.equals("zhang")) throw new UnknownAccountException("Realm3 用户名错误"); if(!passWord.equals("123")) throw new IncorrectCredentialsException("Realm4 密码错误"); return new SimpleAccount("zhang@163.com", passWord, getName()); } }
- 测试
package test; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.Subject; public class TestMain { public static void main(String[] args) { SecurityManager securityManager=new IniSecurityManagerFactory("classpath:shiro.ini").getInstance(); SecurityUtils.setSecurityManager(securityManager); Subject subject=SecurityUtils.getSubject(); AuthenticationToken token=new UsernamePasswordToken("zhang","123"); try { subject.login(token); PrincipalCollection ps=subject.getPrincipals(); System.out.println(ps.asList()); System.out.println(ps.getRealmNames()); System.out.println(subject.getPrincipal().toString()); } catch (UnknownAccountException e) { System.out.println(e.getMessage()); }catch(IncorrectCredentialsException e){ System.out.println(e.getMessage()); } } }
- 结果:
因为是FirstSuccessfulStrategy策略,myRealm1认证成功,所以只返回这个Realm的认证信息,其他的省略。
- 修改shiro.ini,认证策略修改为AtLeastOneSuccessfulStrategy ,其他文件均不变
[main] authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator securityManager.authenticator=$authenticator atLeastOneSuccessfulStrategy=org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy securityManager.authenticator.authenticationStrategy=$atLeastOneSuccessfulStrategy myRealm1=realms.MyRealm1 myRealm2=realms.MyRealm2 myRealm3=realms.MyRealm3 securityManager.realms=$myRealm1,$myRealm2,$myRealm3 [users] zhang=123 wang=123
- 修改shiro.ini,认证策略修改为AllSuccessfulStrategy,其他文件均不变
[main] authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator securityManager.authenticator=$authenticator atLeastOneSuccessfulStrategy=org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy securityManager.authenticator.authenticationStrategy=$atLeastOneSuccessfulStrategy myRealm1=realms.MyRealm1 myRealm2=realms.MyRealm2 myRealm3=realms.MyRealm3 securityManager.realms=$myRealm1,$myRealm2,$myRealm3 [users] zhang=123 wang=123