示例
- 调用链:开始用户验证login()->AbstractAuthenticaticator.authenticate()->子类ModularRealmAuthenticator.doAuthenticate()判断有几个Realm,然后一个个执行->getAuthenticationInfo()->AuthenticatingRealm.getAuthenticationInfo()->MyRealm.doGetAuthenticationInfo()到此完成用户验证->
- 开始授权BitAndWildPermissionResolver.resolvePermission()解析所需权限->MyRealm.doGetAuthorizationInfo()获取用户权限->BitAndWildPermissionResolver.resolvePermission()解析用户权限中存在的字符串权限+user2+10、user2:*->MyRolePermissionResolver.resolvePermissionInRole()解析用户角色role1、role2的权限,返回menu:*
- 根据调用链从外到内
AuthorizerTest:测试类
public class AuthorizerTest extends BaseTest { /** * @Author haien * @Description 测试MyRealm自己设置角色权限的授权方式 * @Date 2019/2/19 * @Param [] * @return void **/ @Test public void testIsPermitted(){ login("classpath:config/shiro-jdbc-authorizer.ini","zhang","123"); Assert.assertTrue(subject().isPermitted("user1:update")); Assert.assertTrue(subject().isPermitted("user2:update")); Assert.assertTrue(subject().isPermitted("+user1+2")); //新增 Assert.assertTrue(subject().isPermitted("+user1+8")); //查看 Assert.assertTrue(subject().isPermitted("+user2+10")); //新增与查看 Assert.assertFalse(subject().isPermitted("+user1+4")); //没有删除权限 //MyRolePermissionResolver解析得到的权限 Assert.assertTrue(subject().isPermitted("menu:view")); } }
MyRealm:doGetAuthenticationInfo()被login()调用,完成用户验证
public class MyRealm extends AuthorizingRealm { //继承AuthorizingRealm实现Realm接口 /** * @Author haien * @Description 获取身份验证信息(和MyRealm1一样) * @Date 2019/2/19 * @Param [authenticationToken] * @return org.apache.shiro.authc.AuthenticationInfo **/ @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken authenticationToken) throws AuthenticationException { String username=(String)authenticationToken.getPrincipal(); //得到用户名 String password=new String((char[])authenticationToken.getCredentials()); //得到密码 //String password=(String)authenticationToken.getCredentials(); //若用户名错误 if(!"zhang".equals(username)){ throw new UnknownAccountException(); } //若密码错误 if(!"123".equals(password)){ throw new IncorrectCredentialsException(); } //身份验证成功,返回一个AuthenticationInfo实现 return new SimpleAuthenticationInfo(username,password,getName()); } }
如果想用数据库而不是自己准备用户和权限的话,可以配置shiro-jdbc-authorizer.ini,替换shiro-authorizer.ini和MyRealm类
[main] ;自定义Authorizer authorizer=org.apache.shiro.authz.ModularRealmAuthorizer ;自定义permissionResolver permissionResolver=com.haien.shiroHelloWorld.permission.BitAndWildPermissionResolver authorizer.permissionResolver=$permissionResolver ;自定义rolePermissionResolver rolePermissionResolver=com.haien.shiroHelloWorld.permission.MyRolePermissionResolver authorizer.rolePermissionResolver=$rolePermissionResolver securityManager.authorizer=$authorizer ;以上都和shiro-authorizer.ini一样 ;自定义JdbcRealm; ;一定要放在SecurityManager。authorizer,因为调用setRealms()会将realms设置给Authorizer, ;并将前面给Authorizer设置的属性permissionResolver和RolePermissionResolver设置给realms jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm dataSource=com.alibaba.druid.pool.DruidDataSource dataSource.driverClassName=com.mysql.jdbc.Driver dataSource.url=jdbc:mysql://localhost:3306/shiro dataSource.username=root dataSource.password=123456 jdbcRealm.dataSource=$dataSource jdbcRealm.permissionsLookupEnabled=true //开启权限从数据库查找功能 securityManager.realms=$jdbcRealm
BitAndWildPermissionResolver:解析权限字符串(用户拥有的权限和要求的权限)
/** * @Author haien * @Description 解析权限字符串:根据字符串是否以+开头解析为BitPermission或WildcardPermission * @Date 2019/2/19 **/ public class BitAndWildPermissionResolver implements PermissionResolver { /** * @Author haien * @Description 根据字符串是否以+开头解析为BitPermission或WildcardPermission * @Date 2019/2/19 * @Param [s] * @return org.apache.shiro.authz.Permission **/ @Override public Permission resolvePermission(String permissionString) { if(permissionString.startsWith("+")){ return new BitPermission(permissionString); } return new WildcardPermission(permissionString); } }
其中BitPermission实现了Permission接口
- Permission接口
public interface Permission {
//权限匹配
boolean implies(Permission var1);
}
this是用户拥有的权限,var1是所需权限,当this是user:*或user,var1是user:create或两者完全相同时,返回true。
BitPermission
/** * @Author haien * @Description 实现位移方式的权限定义,解析要求的权限。被BitAndWildPermissionResolver调用。 * 规则:+资源+权限位。以+开头,中间通过+分隔; * 权限位:0-all权限(二进制0000),1-新增(0001),2-修改(0010), * 4-删除(0100)、8-查看(1000);如,+user+10,由于10二进制为1010, * 1位置与2、8相同,按位与返回二进制数非0,所以表示拥有修改、查看权限 * @Date 2019/2/18 **/ public class BitPermission implements Permission { //资源 private String resourceIdentify; //权限位 private int permissionBit; //实例id private String instanceId; public BitPermission(String permissionString) { //解析要求的权限字符串 String[] array=permissionString.split("\\+"); //加//防止+被解析 if(array.length>1){ resourceIdentify=array[1]; //第0个为空 } if(StringUtils.isEmpty(resourceIdentify)){ //开头两个+相连,或者length<=1,即根本没定义权限 resourceIdentify="*"; } if(array.length>2){ permissionBit=Integer.valueOf(array[2]); }//peimissionBit为空的话即默认值0,不用赋*给它,后面用0来判断即可 if(array.length>3){ instanceId=array[3]; } if(StringUtils.isEmpty(instanceId)){ instanceId="*"; } } /** * @Author haien * @Description 判断用户是否拥有权限 * @Date 2019/2/18 * @Param [p所需权限](this为用户权限) * @return boolean **/ @Override public boolean implies(Permission p) { if(!(p instanceof BitPermission)) { return false; } BitPermission other=(BitPermission)p; if(!("*".equals(this.resourceIdentify) //this:用户拥有的权限,other:所需权限 ||this.resourceIdentify.equals(other.resourceIdentify))){ return false; } if(!(this.permissionBit==0||(this.permissionBit&other.permissionBit)!=0)){ return false; } if(!("*".equals(this.instanceId)||this.instanceId.equals(other.instanceId))){ return false; } return true; } }
MyRealm:doGetAuthorizationInfo()获取用户权限。
public class MyRealm extends AuthorizingRealm { //继承AuthorizingRealm实现Realm接口 /** * @Author haien * @Description 根据用户身份获取授权信息 * @Date 2019/2/19 * @Param [principalCollection] * @return org.apache.shiro.authz.AuthorizationInfo **/ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { SimpleAuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo(); /*不从数据库查找,自己设置权限进去*/ //用户拥有两个角色 authorizationInfo.addRole("role1"); //添加角色后调用MyRolePermissionResolver解析出权限 authorizationInfo.addRole("role2"); //解析出来后应该是添加回authorizationInfo的权限集合 //四个权限 authorizationInfo.addObjectPermission(new BitPermission("+user1+10")); authorizationInfo.addObjectPermission(new WildcardPermission("user1:*")); authorizationInfo.addStringPermission("+user2+10"); //10代表2新增与8查看 authorizationInfo.addStringPermission("user2:*"); //字符串权限,等下会调用BitAndWildPermissionResolver解析 return authorizationInfo; } }
其中,Principle原本是AuthenticationToken的属性之一,表示用户名。
MyRolePermissionResolver:解析角色字符串到用户权限集合
public class MyRolePermissionResolver implements RolePermissionResolver { /** * @Author haien * @Description 如果用户拥有role1,则返回menu:*权限,添加到用户权限集合中 * @Date 2019/2/19 * @Param [roleString] * @return java.util.Collection<org.apache.shiro.authz.Permission> **/ @Override public Collection<Permission> resolvePermissionsInRole(String roleString) { if("role1".equals(roleString)){ //role1的权限(在MyRealm中添加也一样) /* return Arrays.asList(new WildcardPermission("menu:*"), new BitPermission("+user1+10"), new WildcardPermission("user1:*"), new BitPermission("+user2+10"), new WildcardPermission("user2:*")); */ return Arrays.asList((Permission)new WildcardPermission("menu:*")); } return null; } }
- 代码实例:ideaProjects/shiroHelloWorld
- 《跟我学shiro第三章