这一节是属于授权的内容,我们的例子是要说明如何判断主体是否有相应的角色和权限。

判断主体是否有相应的角色和权限

  • 判断主体是否有相应的角色
  • 判断主体是否有相应的权限

判断主体是否有相应的角色和权限

先把上一节写好的登录逻辑封装成一个工具类:

public class ShiroUtil {

public static Subject login(String configFile,String userName,String passwoord){
// 注意:这里 SecurityManager 所在的包名
// 读取配置文件,初始化SecurityManager工厂
Factory<SecurityManager> factory = new IniSecurityManagerFactory(configFile);
SecurityManager securityManager = factory.getInstance();
// 把 securityManager 的实例绑定到 SecurityUtils 上
SecurityUtils.setSecurityManager(securityManager);
// 得到当前执行的用户
Subject currentUser = SecurityUtils.getSubject();
// 自己创建一个令牌
UsernamePasswordToken token = new UsernamePasswordToken(userName,passwoord);
try {
// 身份认证
currentUser.login(token);
System.out.println("身份认证成功");
} catch (AuthenticationException e) {
e.printStackTrace();
}
return

判断主体是否有相应的角色

配置文件片段:

[users]
#表示内存中有一个用户(用户名 demo1,密码 1234),他的角色是 role1 、role2
demo1=1234,role1,role2
demo2=1234,role1

我们可以看到一个用户具有的角色是通过一个字符串的集合来表示的。

测试代码:

public class RoleTest


/**
* 测试是否有角色,测试方法 hasRole
*/
@Test
public void testHasRole(){
Subject currentUser = ShiroUtil.login("classpath:shiro.ini","demo1","1234");
System.out.println(currentUser.hasRole("role1"));
System.out.println(currentUser.hasRole("role2"));
// 测试是否分别有三个角色
boolean[] results = currentUser.hasRoles(Arrays.asList("role1","role2","role3"));
for(boolean result:results){
System.out.println(result);
}
// 区别上面的方法,下面的方法测试的是,一个角色是否同时拥有指定的几个角色 System.out.println(currentUser.hasAllRoles(Arrays.asList("role1","role2")));
System.out.println(currentUser.hasAllRoles(Arrays.asList("role1","role2","role3")));
currentUser.logout();
}


/**
* 与上面的方法的不同之处在于,角色验证没有通过,抛出运行时异常
*/
@Test
public void testCheckRole(){
Subject currentUser = ShiroUtil.login("classpath:shiro.ini","demo1","1234");
currentUser.checkRole("role1");
currentUser.checkRole("role2");
currentUser.checkRoles(Arrays.asList("role1","role2"));
// 下面的代码抛出 org.apache.shiro.authz.UnauthorizedException 异常
currentUser.checkRoles("role1","role2","role3");
}
}

判断主体是否有相应的权限

配置文件片段:

[users]
demo1=123456,role1,role2
demo2=123456,role1
[roles]
role1=user:select
role2=user:add,user:update,user:delete

测试代码:

public class PermissionTest {

@Test
public void testIsPermitted(){
Subject currentUser = ShiroUtil.login("classpath:shiro.ini", "demo1", "1234");
System.out.println(currentUser.isPermitted("user:select"));
System.out.println(currentUser.isPermitted("user:update"));
System.out.println(currentUser.isPermitted("user:add"));
System.out.println(currentUser.isPermitted("user:delete"));
// 测试是否分别有指定的权限
boolean[] results = currentUser.isPermitted("user:select","user:update","user:add","user:delete");
for(boolean result:results){
System.out.println(result);
}
// 测试是否拥有全部的权限
System.out.println(currentUser.isPermittedAll("user:select","user:update","user:add","user:delete"));
currentUser.logout();
}


@Test
public void testCheckPermitted(){
Subject currentUser = ShiroUtil.login("classpath:shiro.ini", "demo", "1234");
currentUser.checkPermission("user:select");
currentUser.checkPermissions("user:select","user:update","user:add","user:delete");
currentUser.logout();
}
}

Shiro 支持三种方式的授权:
编程式:通过写if/else 授权代码块完成:

Subject subject = SecurityUtils.getSubject();
if(subject.hasRole(“admin”)) {
//有权限
} else {
//无权限

注解式:通过在执行的Java方法上放置相应的注解完成:

@RequiresRoles("admin")
public void hello() {
//有权限
//方法返回 字符串,字符串就是逻辑视图名,Model作用是将数据填充到request域,在页面展示
@RequestMapping(value="/editItems",method={RequestMethod.GET})
@RequiresPermissions("item:update")//执行此方法需要"item:update"权限
public String editItems(Model model,Integer id)throws

JSP/GSP 标签:在JSP/GSP 页面通过相应的标签完成:

<shiro:hasRole name="admin">
<!—
</shiro:hasRole>
Jsp页面添加:
<%@ tagliburi="http://shiro.apache.org/tags" prefix="shiro"

标签名称 标签条件(均是显示标签内容)
<shiro:authenticated> 登录之后
<shiro:notAuthenticated> 不在登录状态时
<shiro:guest> 用户在没有RememberMe时
<shiro:user> 用户在RememberMe时
<shiro:hasAnyRoles name="abc,123" 在有abc或者123角色时
<shiro:hasRole name="abc"> 拥有角色abc
<shiro:lacksRole name="abc"> 没有角色abc
<shiro:hasPermission name="abc"> 拥有权限资源abc
<shiro:lacksPermission name="abc"> 没有abc权限资源
<shiro:principal> 显示用户身份名称
<shiro:principal property="username"/>

配置shiro-permission.ini
shiro-permission.ini里边的内容相当于在数据库

create、update权限
role1=user:create,user:update
#角色role2对资源user拥有create、delete权限
role2=user:create,user:delete
#角色role3对资源user拥有create权限
role3=user:create

标识符号规则:资源:操作:实例(中间使用半角:分隔)
user:create:01 表示对用户资源的01实例进行create操作。

user:create:表示对用户资源进行create操作,相当于user:create:*,对所有用户资源实例进行create操作。

user:*:01 表示对用户资源实例01进行所有操作。

流程
当调用controller的一个方法,由于该 方法加了@RequiresPermissions(“item:query”) ,shiro调用realm获取数据库中的权限信息,看”item:query”是否在权限数据中存在,如果不存在就拒绝访问,如果存在就授权通过。

当展示一个jsp页面时,页面中如果遇到,shiro调用realm获取数据库中的权限信息,看item:update是否在权限数据中存在,如果不存在就拒绝访问,如果存在就授权通过。

问题:只要遇到注解或jsp标签的授权,都会调用realm方法查询数据库,需要使用缓存解决此问题。