(4)shiro多个realm
shiro支持多个realm,当设置多个realm的时候,shiro的认证和授权的步骤是怎样的呢。
多个realm认证原理:
发现需要在执行认证的时候,需要策略来处理多个realm存在的情况。默认实现类有三个策略:
1. AtLeastOneSuccessfulStrategy :如果一个(或更多)Realm 验证成功,则整体的尝试被认为是成功的。如果没有一个验证成功,则整体尝试失败。
2. FirstSuccessfulStrategy 只有第一个成功地验证的Realm 返回的信息将被使用。后面的realm会被忽略,如果一个都没有成功则失败。
3. AllSucessfulStrategy 为了整体的尝试成功,所有配置的Realm 必须验证成功。如果没有一个验证成功,则整体尝试失败。
ModularRealmAuthenticator 默认的是AtLeastOneSuccessfulStrategy
多个realm授权原理:
当shiro判断是否有对应的角色或者资源的时候,最底层是调用Authenticator的doAuthenticate方法。
下面是Authenticator的一个实现类(ModularRealmAuthenticator)当有多个realms的时候执行的步骤:
得到总结:只要有一个realm里面有这个角色或者资源就代表有这个权限
代码测试
1,新增一个realm2,无论如何都是通过的,返回的principal固定为test(自己可以根据业务需要,为当前登录的用户设置别的身份)
public class MyRealm2 extends AuthorizingRealm { //认证信息, @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken upToken = (UsernamePasswordToken) token; String password = new String(upToken.getPassword()); //模拟用户名密码是否正确 return new SimpleAuthenticationInfo("test",password,getName()); } //授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { //获取用户名 String username = (String)getAvailablePrincipal(principals); //模拟从数据库查询出来对应的角色和权限 Set<String> roles = new HashSet<String>(); roles.add("role_3"); roles.add("role_4"); Set<String> permissions = new HashSet<String>(); permissions.add("user:update"); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.setRoles(roles); info.setStringPermissions(permissions); return info; }
2配置文件
myrealm=com.nfcm.shiro.Realm.MyRealm myrealm2=com.nfcm.shiro.Realm.MyRealm2 #设置策略,必须所有的realm都通过 authcStrategy=org.apache.shiro.authc.pam.AllSuccessfulStrategy #配置认证器 authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator #将验证器和策略关联起来 authenticator.authenticationStrategy=$authcStrategy #注入认证器 securityManager.authenticator=$authenticator #设置realm,这个要最后设置,如果后设置认证器或者授权器,则里面的realms都是空的 securityManager.realms=$myrealm,$myrealm2
3.测试代码
ShiroUtils.login("classpath:shiro-myrealm2.ini","zhang","123456"); Subject subject = SecurityUtils.getSubject(); List<String> principals =subject.getPrincipals().asList(); for (String principal:principals) { System.out.println(principal); } System.out.println(subject.getPrincipals().getPrimaryPrincipal()); //是否通过认证 System.out.println(subject.isAuthenticated()); //是否有role1角色 System.out.println(subject.hasRole("role_1")); //realm2里面的角色 System.out.println(subject.hasRole("role_3")); System.out.println(subject.isPermitted("user:create")); //realm2里面的资源 System.out.println(subject.isPermitted("user:update"));
最后输出结果:
zhang
test
zhang
true
true
true
true
true
getPrimaryPrincipal方法获取的是第一个realm里面的身份。
subject.getPrincipals().fromRealm(“myrealm2”)可以获取指定的realm里面的身份信息,返回的是一个集合,获取第一个即可。
github代码地址
https://github.com/cmniefei/shiroparent