最常用的权限标识:【资源 :操作】
1> user:query , user:insert , order:delete , menu:show 【:】 作为分隔符,分隔资源和操作【资源:操作】 【,】 作为分隔,分隔多个权限【权限1,权限2,权限3】 2> user:* , *:query 【*】 作为通配符,代表所有操作、资源 【user:* 即user的所有操作】 【*:query 即所有资源的查询操作】 3> * 【代表一切资源的一切权限 = 最高权限】 4> 细节: 1)【user:* 可以匹配 user:xx, user:xx:xxx】 【*:query 只可以匹配 xx:query,不能匹配 xx:xx:query. 除非 *:*:query】 2)【user:update,user:insert】 可以简写为 【"user:update,insert"】 [roles] manager1=user:query,user:update,user:insert manager2="user:query,update,insert" #注意要加引号 #如上manager1和manager2权限等价 #subject.isPermittedAll("user:update","user:insert","user:query")实例级权限标识:【资源 :操作 :实例】,粒度细化到具体某个资源实例
1> user:update:1 , user:delete:1 # 对用户1可以update,对用户1可以delete 2> "user:update,delete:1" #和上面等价 # subject.isPermittedAll("user:update,delete:1","user:update:1","user:delete:1") 3> user:*:1 , user:update:* , user:*:* 四、自定义Realm存在的问题:目前所有的 用户、角色、权限数据都在ini文件中,不利于管理。
实际项目开发中这些信息,应该在数据库中。所以需要为这3类信息建表
4.1 建表用户表,角色表,权限表
create table t_user( id int primary key auto_increment, username varchar(20) not null unique, password varchar(100) not null )engine=innodb default charset=utf8; create table t_role( id int primary key auto_increment, role_name varchar(50) not null unique, create_time timestamp not null )engine=innodb default charset=utf8; create table t_permission( id int primary key auto_increment, permission_name varchar(50) not null unique, create_time timestamp )engine=innodb default charset=utf8; create table t_user_role( id int primary key auto_increment, user_id int references t_user(id), role_id int references t_role(id), unique(user_id,role_id) )engine=innodb default charset=utf8; create table t_role_permission( id int primary key auto_increment, permission_id int references t_user(id), role_id int references t_role(id), unique(permission_id,role_id) )engine=innodb default charset=utf8; 4.2 自定义RealmRealm的职责是,为shiro加载 用户,角色,权限数据,以供shiro内部校验。
之前定义在ini中的数据,默认有IniRealm去加载。
现在库中的数据,需要自定义Realm去加载。
ops : 没必要在Realm中定义大量的查询数据的代码,可以为Realm定义好查询数据的DAO和Service。
4.2.1 父类如下是Realm接口的所有子类,其中IniRealm是默认的Realm,负责加载shiro.ini中的[users]和[roles]信息,当shiro需要用户,角色,权限信息时,会通过IniRealm获得。****
自定义realm有两个父类可以选择:
1> 如果realm只负责做身份认证 ,则可以继承:AuthenticatingRealm
2> 如果realm要负责身份认证和权限校验,则可以继承:AuthorizingRealm
4.2.2 定义Realm public class MyRealm extends AuthorizingRealm { /** * 是否支持某种token * @param token * @return */ @Override public boolean supports(AuthenticationToken token) { System.out.println("is support in realm1"); if(token instanceof UsernamePasswordToken){ return true; } return false; } /** * 当subject.login()时,shiro会调用Realm的此方法做用户信息的查询,然后做校验 * 职责:通过用户传递来的用户名查询用户表,获得用户信息 * 返回值:将查到的用户信息(用户名+密码)封装在AuthenticationInfo对象中返回 * 异常:如果没有查到用户可抛出用户不存在异常;如果用户被锁定可抛出用户被锁异常;或其它自定义异常. * @param token * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { //获得用户名 String username = (String) token.getPrincipal(); System.out.println("user:"+username+" is authenticating~~"); UserService userService = (UserService)ContextLoader.getCurrentWebApplicationContext().getBean("userService"); //身份认证 User user = userService.queryUser(username); System.out.println("user:"+user); /** 如果查询结果为空,直接返回null即可, shiro的后续流程有null判断逻辑,为null时会抛出UnknownAccountException **/ if(user == null){ return null; } // 将 当前用户的认证信息存入 SimpleAuthenticationInfo 并返回 // 注意此方法的本职工作就是查询用户的信息,所以查到后不用比对密码是否正确,那是shiro后续流程的职责。 // 如果密码错误,shiro的后续流程中会抛出异常IncorrectCredentialsException return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(),getName()); /** 补充: 可以在user表中增加一列,用于存储用户是否被锁定,则查询的User对象中会有是否锁定的属性 如果发现锁定则可以在此方法中抛出异常:LockedAccountException, **/ } /** * 当触发权限或角色校验时:subject.isPermitted() / subject.checkPermission(); * subject.hasRole() / subject.checkRole() 等。 * 此时需要数据库中的 权限和角色数据,shiro会调用Realm的此方法来查询 * 角色和权限信息存入SimpleAuthorizationInfo对象 * @param principals * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { //获得username String username = (String)principals.getPrimaryPrincipal(); //新建SimpleAuthorizationInfo对象 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //查询当前用户的所有 "角色" 和 "权限" UserService userService = (UserService)ContextLoader.getCurrentWebApplicationContext().getBean("userService"); Set<String> roles = userService.queryRolesByUsername(username); Set<String> perms = userService.queryPermissionsByUsername(username); //“角色” 和 “权限” 存入 SimpleAuthorizationInfo对象 info.setRoles(roles); info.setStringPermissions(perms); //返回SimpleAuthorizationInfo return info; } } 4.3 配置Realmshiro.ini中 配置自定义Realm