1、授权简介

授权,也称访问控制,在应用中控制谁能访问哪些资源(如访问页面、编辑数据、等)。在授权中需了解的几个关键词:主体(subject)、资源(resource)、权限(permission)、角色(role)。

主体

主体,访问应用的用户,在 Shiro 中使用 Subject 代表该用户。用户只有授权后才允许访问相应的资源。

资源

在应用中用户可以访问的任何东西,比如访问 JSP 页面、CRUD数据、访问接口、打印等等都是资源。用户只有通过授权后才能访问。

权限

通过权限我们可以表示在应用中用户有没有操作某个资源的权力。即权限表示在应用中用户能不能访问某个资源,如: 访问用户列表页面、CRUD数据、打印文档等。

角色

角色代表了用户操作权限集合。一般情况下我们会赋予用户角色而不是权限,即这样用户可以拥有多个权限。如:项目经理、技术总监、部门经理、主管等都是角色,不同的角色拥有多个不同的权限。

隐式角色:

直接通过角色来验证用户有没有操作权限,在实际应用中技术总监、主管可以使用打印机,假设某天不允许主管使用打印机,此时需要从应用中删除相应逻辑代码。粒度较粗。

显示角色:

在程序中通过权限控制谁能访问某个资源,即角色拥有多个权限,这样假设哪个角色不能访问某个资源,只需要从角色拥有权限中移除即可。无须修改多处代码,即粒度是以资源-实例为单位的;粒度较细。

2、 授权方式

Shiro 支持三种方式的授权。

1)编程式:通过写 if/else 授权代码块完成。

//1. 从 PrincipalCollection 中来获取登录用户的信息

Object principal = arg0.getPrimaryPrincipal();

//2. 利用登录的用户的信息来获取当前用户的角色或权限

Set<String> roles = new HashSet<>();

roles.add("user");

if("admin".equals(principal)){

roles.add("admin");

}

/

2)注解式:通过在执行的方法上注解完成。

@RequiresRoles("user")

public void user() {

//有权限

}

3)JSP标签:在 JSP页面通过相应的标签完成。(jsp已过时了,现在是前后端分离)

<shiro:hasRole name="user">

<!— 有权限 —>

</shiro:hasRole>

3、 授权

1) 基于角色的访问控制。

在 ini 配置文件配置用户拥有的角色,格式:用户名=密码,角色1,角色2。

[users]

zhang=123456,role1,role2

wang=123456,role1

Shiro 提供了 hasRole/hasAllRoles用于判断用户是否拥有某个角色。

// 1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager

factory<org.apache.shiro.mgt.SecurityManager> factory =

new IniSecurityManagerFactory("classpath:shiro.ini");

// 2、得到SecurityManager实例 并绑定给SecurityUtils

org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();

SecurityUtils.setSecurityManager(securityManager);

// 3、得到Subject及创建用户名/密码身份验证Token

Subject subject = SecurityUtils.getSubject();

UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123456");

try {

// 4、登录,身份验证

subject.login(token);

} catch (AuthenticationException e) {

// 5、身份验证失败

logger.info("用户名 、密码错误");

}

if(subject.hasRole("role1")){

logger.info(token.getUsername() " has role1");

}else{

logger.info(token.getUsername() " hasn't role1");

}

2) 基于资源(权限)的访问控制

在 ini 配置文件配置用户拥有的角色及角色-权限关系,格式:"角色=权限 1,权限 2"。

首先根据用户名找到角色,然后根据角色再找到权限,即角色是权限的组合。

[users]

zhang=123456,role1,role2

wang=123456,role1

[roles]

role1=user:create,user:update

role2=user:create,user:delete

Shiro 提供了 isPermitted 和 isPermittedAll 用于判断用户是否拥有某个权限或所有权限。

if(subject.isPermitted("user:create")){

logger.info(token.getUsername() " has user:create");

}else{

logger.info(token.getUsername() " hasn't user:create");

}

4、 授权流程

shiro授权测试(Shiro授权及Realm的使用)(1)

1)首先调用 subject.isPermitted*/hasRole*接口,其会委托给 SecurityManager,而 SecurityManager 接着会委托给 Authorizer。

2)Authorizer 是真正的授权者,如果我们调用如 isPermitted("user:view"),其首先会通过 PermissionResolver 把字符串转换成相应的 Permission 实例;

在进行授权之前,其会调用相应的 Realm 获取 Subject 相应的角色、权限用于匹配传入的角色、权限;

3) Authorizer 会判断 Realm 的角色、权限是否和传入的匹配,如果有多个 Realm,会委托给 ModularRealmAuthorizer 进行循环判断,如果匹配如 isPermitted*/hasRole* 会返回 true,否则返回 false 表示授权失败。

ModularRealmAuthorizer 进行多 Realm 匹配流程

1)首先检查相应的 Realm 是否实现了实现了 Authorizer;

2)如果实现了 Authorizer,那么接着调用其相应的 isPermitted*/hasRole* 接口进行匹配;

3)如果有一个 Realm 匹配那么将返回 true,否则返回 false。

5、Realm 授权

1、自定义类JdbcRealm继续父AuthorizingRealm,重写doGetAuthorizationInfo授权方法,根据授权的用户在数据库中查询所拥有的角色、权限。

shiro授权测试(Shiro授权及Realm的使用)(2)

2、 当我们调用hasRole("普通员工")方法时,Authorizer 会调用doGetAuthorizationInfo()方法进行授权,判断 Realm 的角色、权限是否和传入的匹配,如果匹配,hasRole("普通员工")返回true,否则返回false。

shiro授权测试(Shiro授权及Realm的使用)(3)

3、 测试结果

shiro授权测试(Shiro授权及Realm的使用)(4)

,