本文共 3525 字,大约阅读时间需要 11 分钟。
授权是什么
授权,也叫访问控制,即在应用中控制谁访问哪些资源(如访问页面/编辑数据/页面操作 等)。在授权中需了解的几个关键对象:主体(Subject)、资源(Resource)、权限(Permission)、角色(Role)。
- 主体(Subject):访问应用的用户,在 Shiro 中使用 Subject 代表该用户。用户只有授权后才允许访问相应的资源。
- 资源(Resource):在应用中用户可以访问的 URL,比如访问 JSP 页面、查看/编辑某些数据、访问某个业务方法、打印文本等等都是资源。用户只要授权后才能访问。
- 权限(Permission):安全策略中的原子授权单位,通过权限我们可以表示在应用中用户有没有操作某个资源的权力。即权限表示在应用中用户能不能访问某个资源,如:访问用户列表页面查看/新增/修改/删除用户数据(即很多时候都是CRUD(增查改删)式权限控制)等。权限代表了用户有没有操作某个资源的权利,即反映在某个资源上的操作允不允许。
- Shiro 支持粗粒度权限(如用户模块的所有权限)和细粒度权限(操作某个用户的权限,即实例级别的)
- 角色(Role):权限的集合,一般情况下会赋予用户角色而不是权限,即这样用户可以拥有一组权限,赋予权限时比较方便。不同的角色拥有一组不同的权限。
授权的方式
- 编程式:通过写if/else 授权代码块完成
- 注解式:通过在执行的Java方法上放置相应的注解完成,没有权限将抛出相应的异常
- JSP/GSP 标签:在JSP/GSP 页面通过相应的标签完成
代码案例实现
在前文的基础上进行授权管理,在配置文件当中对俩个界面进行不同的权限给予。表示当只有使用这个角色才能对页面进行访问。
权限添加之后添加这俩个页面,在登录之后的list.jsp当中使用a标签进行指向。
以及在ShiroRealm 类当中进行继承 AuthorizingRealm 类,重写doGetAuthorizationInfo方法:对权限进行分析:
@Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { System.out.println("没有权限,进行授权。"); //从PrincipalCollection获取信息 Object principal=principals.getPrimaryPrincipal(); //用信息获取权限 Set roles= new HashSet (); roles.add("user"); if ("admin".equals(principal)) { roles.add("admin"); } //创建SimpleAuthorizationInfo接口并设置对应的Reles属性 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles); //返回对象 return info; }
配置完成之后就可以运行查看效果了,当使用admin进行登录的时候admin.jsp和user.jsp都能访问,而使用user进行登录,只能访问user.jsp页面。
授权的流程
- 首先调用 Subject.isPermitted*/hasRole* 接口,其会委托给SecurityManager,而 SecurityManager 接着会委托给 Authorizer;
- Authorizer是真正的授权者,如果调用如isPermitted(“user:view”),其首先会通过 PermissionResolver 把字符串转换成相应的 Permission 实例;
- 在进行授权之前,其会调用相应的 Realm 获取 Subject 相应的角色/权限用于匹配传入的角色/权限;
- Authorizer 会判断 Realm 的角色/权限是否和传入的匹配,如果有多个Realm,会委托给 ModularRealmAuthorizer 进行循环判断,如果匹配如 isPermitted*/hasRole* 会返回true,否则返回false表示授权失败。
Shiro 标签
Shiro 提供了 JSTL 标签用于在 JSP 页面进行权限控制,如根据登录用户显示相应的页面按钮。
- guest 标签:用户没有身份验证时显示相应信息,即游客访问信息。
- user 标签:用户已经经过认证/记住我登录后显示相应的信息。
- authenticated 标签:用户已经身份验证通过,即Subject.login登录成功,不是记住我登录的。
- notAuthenticated 标签:用户未进行身份验证,即没有调用Subject.login进行登录,包括记住我自动登录的也属于未进行身份验证。
- pincipal 标签:显示用户身份信息,默认调用Subject.getPrincipal() 获取,即 Primary Principal。
- hasRole 标签:如果当前 Subject 有角色将显示 body 体内容。
- hasAnyRoles 标签:如果当前Subject有任意一个角色(或的关系)将显示body体内容。
- lacksRole:如果当前 Subject 没有角色将显示 body 体内容。
- hasPermission:如果当前 Subject 有权限将显示 body 体内容。 10.lacksPermission:如果当前Subject没有权限将显示body体内容。
shiro 标签的使用
第一步导入shiro包:
<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags"%>
第二步使用:如下图所示
权限注解
- @RequiresAuthentication:表示当前Subject已经通过login 进行了身份验证;即 Subject. isAuthenticated() 返回 true
- @RequiresUser:表示当前 Subject 已经身份验证或者通过记住我登录的。
- @RequiresGuest:表示当前Subject没有身份验证或通过记住我登录过,即是游客身份。
- @RequiresRoles(value={“admin”, “user”}, logical= Logical.AND):表示当前 Subject 需要角色 admin 和user
- @RequiresPermissions (value={“user:a”, “user:b”}, logical= Logical.OR):表示当前 Subject 需要权限 user:a 或user:b。
对页面权限再配置
以及可以对页面的权限可以进行封装,如下代码进行封装:
全部注释,使用一个新的属性进行封装;
需要定义一个bean指向那个Map
定义一个bean就需要添加对应的类,com.lzq.shiro.factory.FilterChainDefinitionMapBuilder 包+类
package com.lzq.shiro.factory;import java.util.LinkedHashMap;public class FilterChainDefinitionMapBuilder { public LinkedHashMap buildFilterChainDefinitionMap(){ LinkedHashMap map = new LinkedHashMap<>(); map.put("/login.jsp", "anon"); map.put("/Shiro/Login", "anon"); map.put("/Shiro/Logout", "logout"); map.put("/user.jsp", "authc,roles[user]"); map.put("/admin.jsp", "authc,roles[admin]"); map.put("/list.jsp", "user"); map.put("/**", "authc"); return map; }}
转载地址:http://awqzi.baihongyu.com/