Shiro(五):Shiro 授权

it2024-01-26  67

Shiro(四)介绍Shiro 多Realm验证和认证策略,接下来讲解Shiro 授权。

目录

一、权限配置1.基本概念2.Shiro 授权方式3.默认拦截器4.Permissions5.授权 roles 的配置使用 二、Shiro 实现授权1.授权流程2.实现2.1 修改 ShiroRealm.java2.2 测试

一、权限配置

1.基本概念

授权,也叫访问控制,即在应用中控制谁访问哪些资源(如访问页面/编辑数据/页面操作 等)。

在授权中需了解的几个关键对象:主体(Subject)、资源(Resource)、权限(Permission)、角色(Role)。

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

资源(Resource):在应用中用户可以访问的 URL,比如访问 JSP 页面、查看/编辑某些数据、访问某个业务方法、打印文本等等都是资源。用户只要授权后才能访问。

权限(Permission):安全策略中的原子授权单位,通过权限我们可以表示在应用中用户有没有操作某个资源的权力。即权限表示在应用中用户能不能访问某个资源,如:访问用户列表页面查看/新增/修改/删除用户数据(即很多时候都是CRUD(增查改删)式权限控制)等。权限代表了用户有没有操作某个资源的权利,即反映在某个资源上的操作允不允许。

Shiro 支持粗粒度权限(如用户模块的所有权限)和细粒度权限(操作某个用户的权限,即实例级别的)

角色(Role):权限的集合,一般情况下会赋予用户角色而不是权限,即这样用户可以拥有一组权限,赋予权限时比较方便。典型的如:项目经理、技术总监、CTO、开发工程师等都是角色,不同的角色拥有一组不同的权限。

2.Shiro 授权方式

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

if(subject.hasRole("admin")){ //有权限 }else{ //无权限 }

(2)注解式:通过在执行的Java方法上放置相应的注解完成,没有权限将抛出相应的异常 (常用

@RequiresRoles("admin") public void hello(){ //有权限 }

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

<shiro:hasRole name="admin"> <!--有权限--> </shiro:hasRole>

通过标签可以隐藏没有权限访问的资源

注意:注解式 是常用的方式

3.默认拦截器

Shiro 内置了很多默认的拦截器,比如身份验证、授权等相关的。默认拦截器可以参考org.apache.shiro.web.filter.mgt.DefaultFilter中的枚举 1)默认拦截器: 2)详细区分 ①身份验证相关的(5个) ②授权相关的(5个) ③其他(1个)

4.Permissions

5.授权 roles 的配置使用

新建两个jsp页面:admin.jsp和user.jsp,希望实现访问admin.jsp,需要具备admin的权限,访问user.jsp,需要具备user的权限

步骤: (1)新建两个jsp页面:admin.jsp和user.jsp admin.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <h3>Admin Page</h3> </body> </html>

user.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <h3>User Page</h3> </body> </html>

(2)在list.jsp页面添加访问admin.jsp 和 user.jsp的超链接:

controller:

/** * 进入admin页面 * @return */ @RequestMapping("/toAdmin") public ModelAndView admin(){ return new ModelAndView("admin"); } /** * 进入user页面 * @return */ @RequestMapping("/toUser") public ModelAndView user(){ return new ModelAndView("user"); }

list.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>list</title> </head> <body> <h3>list Page</h3> <div>欢迎登录</div> <a href="toAdmin">Admin page</a><br> <a href="toUser">User page</a><br> <a href="logout">logout</a> </body> </html>

(3)权限配置:在applicationContext.xml文件中 添加 上面两个访问链接的角色过滤 (4)启动项目服务,进行测试: 输入用户名admin,密码123456,点击submit,登录成功,进入list页面,由于上面配置 admin.jsp、user.jsp页面的访问需要 admin 、user角色权限,所以是没有权限访问,会进入unauthorized.jsp页面。user用户登录访问是一样的效果。

二、Shiro 实现授权

1.授权流程

流程如下:

1、首先调用 Subject.isPermitted*/hasRole* 接口,其会委托给SecurityManager,而SecurityManager 接着会委托给 Authorizer;2、Authorizer是真正的授权者,如果调用如isPermitted(“user:view”),其首先会通过 PermissionResolver 把字符串转换成相应的 Permission 实例;3、在进行授权之前,其会调用相应的 Realm 获取 Subject 相应的角色/权限用于匹配传入的角色/权限;4、Authorizer 会判断 Realm 的角色/权限是否和传入的匹配,如果有多个Realm,会委托给 ModularRealmAuthorizer 进行循环判断,如果匹配如 isPermitted*/hasRole* 会返回true,否则返回false表示授权失败。

授权的Realm如何实现? 答:授权需要继承 AuthorizingRealm类,并实现其doGetAuthorizationInfo方法。

注意点:AuthorizingRealm类继承自AuthenticatingRealm,但没有实现AuthenticatingRealm中的doGetAuthenticationInfo方法,所以认证和授权只需要继承AuthorizingRealm就可以了,同时需要实现它的两个抽象方法。

2.实现

ModularRealmAuthorizer 进行多 Realm 匹配流程:

1、首先检查相应的 Realm 是否实现了实现了Authorizer;2、如果实现了 Authorizer,那么接着调用其相应的isPermitted*/hasRole* 接口进行匹配;3、如果有一个Realm匹配那么将返回 true,否则返回 false。

多Realm授权的通过标准:

查看源码: 可以看到 只要有一个授权通过,它就可以进行 return true.

结论:多个Realm授权,只要有一个通过就可以。

2.1 修改 ShiroRealm.java

(1)修改 ShiroRealm的继承类,并实现doGetAuthorizationInfo方法

(2)doGetAuthorizationInfo方法实现

/** * 授权 * 授权会被shiro回调的方法 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { System.out.println("doGetAuthorizationInfo---"); //1. 从 PrincipalCollection 中来获取登录用户的信息 Object principal = principals.getPrimaryPrincipal(); //2. 利用登录用户的信息来获取当前用户的角色或权限(可能需要查询数据库) Set<String> roles= new HashSet<String>(); roles.add("user");//每个用户都有user这个角色 if("admin".equals(principal)){ roles.add("admin");//admin用户还有admin角色 } //3. 创建 SimpleAuthorizationInfo,并设置其 roles 属性 SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(roles); //4. 返回 SimpleAuthorizationInfo 对象 return simpleAuthorizationInfo; }

2.2 测试

(1)admin用户登录,admin.jsp和 user.jsp 两个页面都可以访问:

(2)user用户登录,user.jsp 页面可以访问,而admin.jsp页面没有权限访问 :

测试成功

可点击此处获取源码

最新回复(0)