最常用的权限标识:【资源 :操作】
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 自定义Realm
Realm的职责是,为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 配置Realm
shiro.ini中 配置自定义Realm