将 Shiro 作为应用的权限基础 三:基于注解实现的授权认证过程
授权即访问控制,它将判断用户在应用程序中对资源是否拥有相应的访问权限。
如,判断一个用户有查看页面的权限,编辑数据的权限,拥有某一按钮的权限等等。
一、用户权限模型
为实现一个较为灵活的用户权限数据模型,通常把用户信息单独用一个实体表示,用户权限信息用两个实体表示。
- 用户信息用 LoginAccount 表示,最简单的用户信息可能只包含用户名 loginName 及密码 password 两个属性。实际应用中可能会包含用户是否被禁用,用户信息是否过期等信息。
- 用户权限信息用 Role 与 Permission 表示,Role 与 Permission 之间构成多对多关系。Permission 可以理解为对一个资源的操作,Role 可以简单理解为 Permission 的集合。
- 用户信息与 Role 之间构成多对多关系。表示同一个用户可以拥有多个 Role,一个 Role 可以被多个用户所拥有。
权限声明及粒度
Shiro权限声明通常是使用以冒号分隔的表达式。就像前文所讲,一个权限表达式可以清晰的指定资源类型,允许的操作。同时,Shiro权限表达式支持简单的通配符,可以更加灵活的进行权限设置。
下面以实例来说明权限表达式。
可查询用户数据
User:view
可查询或编辑用户数据
User:view,edit
可对用户数据进行所有操作
User:*或 user
可编辑id为123的用户数据
User:edit:123
授权处理过程
认证通过后接受 Shiro 授权检查,授权验证时,需要判断当前角色是否拥有该权限。
只有授权通过,才可以访问受保护 URL 对应的资源,否则跳转到“未经授权页面”。
如果我们自定义Realm实现,比如我后面的例子中,自定义了ShiroDbRealm类,当访问ShiroDbRealm.doGetAuthorizationInfo()进行授权。
@Controller
@RequestMapping(value = "/user")
public class UserController { @Resource(name="userService")
private IUserService userService; /**
* 测试权限
* 只有拥有 user:create权限,才能进行注册
* @param user
* @return
*/
@RequestMapping(value = "/register")
@ResponseBody
@RequiresPermissions("user:create")
public boolean register(User user){
return userService.register(user);
}
二、授权实现
Shiro支持三种方式实现授权过程:
- 编码实现
- 注解实现
- JSP Taglig实现
1、基于编码的授权实现
1、基于权限对象的实现
创建org.apache.shiro.authz.Permission的实例,将该实例对象作为参数传递给Subject.isPermitted()进行验证。
Permission printPermission = new PrinterPermission("laserjet4400n", "print");
Subject currentUser = SecurityUtils.getSubject();
if (currentUser.isPermitted(printPermission)) {
//show the Print button
} else {
//don't show the button? Grey it out?
}
2、基于字符串的实现
相比笨重的基于对象的实现方式,基于字符串的实现便显得更加简洁。
Subject currentUser = SecurityUtils.getSubject();
if (currentUser.isPermitted("printer:print:laserjet4400n")) {
//show the Print button
} else {
//don't show the button? Grey it out?
}
使用冒号分隔的权限表达式是org.apache.shiro.authz.permission.WildcardPermission默认支持的实现方式。
这里分别代表了资源类型:操作:资源ID
2、基于注解的授权实现
Shiro注解支持AspectJ、Spring、Google-Guice等,可根据应用进行不同的配置。
相关的注解:
@RequiresAuthentication
可以用户类/属性/方法,用于表明当前用户需是经过认证的用户。
@RequiresAuthentication
public void updateAccount(Account userAccount) {
//this method will only be invoked by a
//Subject that is guaranteed authenticated
...
}
@RequiresPermissions
当前用户需拥有制定权限
@RequiresPermissions("account:create")
public void createAccount(Account account) {
//this method will only be invoked by a Subject
//that is permitted to create an account
...
}
3、基于JSP TAG的授权实现
Shiro提供了一套JSP标签库来实现页面级的授权控制。
在使用Shiro标签库前,首先需要在JSP引入shiro标签:
hasRole标签
验证当前用户是否属于该角色
<shiro:hasRole name="administrator">
<a href="admin.jsp">Administer the system</a>
</shiro:hasRole>
hasPermission标签
验证当前用户是否拥有制定权限
<shiro:hasPermission name="user:create">
<a href="createUser.jsp">Create a new User</a>
</shiro:hasPermission>
三、Shiro授权的内部处理机制
1、在应用程序中调用授权验证方法(Subject的isPermitted*或hasRole*等)
2、Sbuject会委托应用程序设置的securityManager实例调用相应的isPermitted*或hasRole*方法。
3、接下来SecurityManager会委托内置的Authorizer的实例(默认是ModularRealmAuthorizer类的实例,类似认证实例)调用相应的授权方法。
4、每一个Realm将检查是否实现了相同的Authorizer 接口。然后,将调用Reaml自己的相应的授权验证方法。
四、授权代码
UserController:处理用户登录后的请求(注册)
package org.shiro.demo.controller; import javax.annotation.Resource; import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.shiro.demo.entity.User;
import org.shiro.demo.service.IUserService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody; @Controller
@RequestMapping(value = "/user")
public class UserController { @Resource(name="userService")
private IUserService userService; /**
* 测试权限
* 只有拥有 user:create 权限,才能进行注册
* @param user
* @return
*/
@RequestMapping(value = "/register")
@ResponseBody
@RequiresPermissions("user:create")
public boolean register(User user){
return userService.register(user);
} /**
* 测试角色
* 只有拥有 administrator 角色,才能跳转到register页面
* @return
*/
@RequestMapping(value = "/toRegister")
@RequiresRoles("administrator")
public String toRegister(){
return "/system/user/register";
}
}
ShiroDbRealm:自定义的指定Shiro验证用户授权的类
packageorg.shiro.demo.service.realm; importjava.util.ArrayList;
importjava.util.List; importjavax.annotation.Resource; importorg.apache.commons.lang.StringUtils;
importorg.apache.shiro.authc.AuthenticationException;
importorg.apache.shiro.authc.AuthenticationInfo;
importorg.apache.shiro.authc.AuthenticationToken;
importorg.apache.shiro.authc.SimpleAuthenticationInfo;
importorg.apache.shiro.authc.UsernamePasswordToken;
importorg.apache.shiro.authz.AuthorizationException;
importorg.apache.shiro.authz.AuthorizationInfo;
importorg.apache.shiro.authz.SimpleAuthorizationInfo;
importorg.apache.shiro.realm.AuthorizingRealm;
importorg.apache.shiro.subject.PrincipalCollection;
importorg.shiro.demo.entity.Permission;
importorg.shiro.demo.entity.Role;
importorg.shiro.demo.entity.User;
importorg.shiro.demo.service.IUserService; /**
* 自定义的指定Shiro验证用户登录的类
* @author TCH
*
*/
publicclass ShiroDbRealm extends AuthorizingRealm{ //@Resource(name="userService")
privateIUserService userService; publicvoid setUserService(IUserService userService) {
this.userService= userService;
} /**
* 为当前登录的Subject授予角色和权限
* @see 经测试:本例中该方法的调用时机为需授权资源被访问时
* @see经测试:并且每次访问需授权资源时都会执行该方法中的逻辑,这表明本例未启用AuthorizationCache
* @seeweb层可以有shiro的缓存,dao层可以配有hibernate的缓存(后面介绍)
*/
protectedAuthorizationInfo doGetAuthorizationInfo(
PrincipalCollectionprincipals) { //获取当前登录的用户名,等价于(String)principals.fromRealm(this.getName()).iterator().next()
Stringaccount = (String) super.getAvailablePrincipal(principals); List<String>roles = new ArrayList<String>();
List<String>permissions = new ArrayList<String>(); //从数据库中获取当前登录用户的详细信息
Useruser = userService.getByAccount(account); if(user!= null){
//实体类User中包含有用户角色的实体类信息
if(user.getRoles() != null && user.getRoles().size() > 0) {
//获取当前登录用户的角色
for(Role role : user.getRoles()) {
roles.add(role.getName());
//实体类Role中包含有角色权限的实体类信息
if(role.getPmss() != null && role.getPmss().size() > 0) {
//获取权限
for(Permission pmss : role.getPmss()) {
if(!StringUtils.isEmpty(pmss.getPermission())){
permissions.add(pmss.getPermission());
}
}
}
}
}
}else{
thrownew AuthorizationException();
} //为当前用户设置角色和权限
SimpleAuthorizationInfoinfo = new SimpleAuthorizationInfo();
info.addRoles(roles);
info.addStringPermissions(permissions); returninfo; } }
将 Shiro 作为应用的权限基础 三:基于注解实现的授权认证过程的更多相关文章
- 将 Shiro 作为应用的权限基础 二:shiro 认证
认证就是验证用户身份的过程.在认证过程中,用户需要提交实体信息(Principals)和凭据信息(Credentials)以检验用户是否合法.最常见的“实体/凭证”组合便是“用户名/密码”组合. 一. ...
- 将 Shiro 作为应用的权限基础 一:shiro的整体架构
将 Shiro 作为应用的权限基础 一:shiro的整体架构 近来在做一个重量级的项目,其中权限.日志.报表.工作量由我负责,工作量还是蛮大的,不过想那么多干嘛,做就是了. 这段时间,接触的东西挺多, ...
- 将 Shiro 作为应用的权限基础 二:基于SpringMVC实现的认证过程
认证就是验证用户身份的过程.在认证过程中,用户需要提交实体信息(Principals)和凭据信息(Credentials)以检验用户是否合法.最常见的“实体/凭证”组合便是“用户名/密码”组合. 一. ...
- 将 Shiro 作为应用的权限基础
Shiro 是 Java 世界中新近出现的权限框架,较之 JAAS 和 Spring Security,Shiro 在保持强大功能的同时,还在简单性和灵活性方面拥有巨大优势.本文介绍了 Shiro 的 ...
- 将 Shiro 作为应用的权限基础 五:SpringMVC+Apache Shiro+JPA(hibernate)整合配置
配置web.xml,applicationContext.xml, spring-mvc.xml,applicationContext-shiro.xml,而且都有详细的说明. Web.xml是web ...
- 将 Shiro 作为应用的权限基础 四:shiro的配置说明
Apache Shiro的配置主要分为四部分: SecurityManager的配置 URL过滤器的配置 静态用户配置 静态角色配置 其中,由于用户.角色一般由后台进行操作的动态数据,比如通过@Req ...
- 【权限管理系统】Spring security(三)---认证过程(原理解析,demo)
在前面两节Spring security (一)架构框架-Component.Service.Filter分析和Spring Security(二)--WebSecurityConfigurer配 ...
- 【原】无脑操作:IDEA + maven + Shiro + SpringBoot + JPA + Thymeleaf实现基础授权权限
上一篇<[原]无脑操作:IDEA + maven + Shiro + SpringBoot + JPA + Thymeleaf实现基础认证权限>介绍了实现Shiro的基础认证.本篇谈谈实现 ...
- django-rest-framework 基础三 认证、权限和频率
django-rest-framework 基础三 认证.权限和频率 目录 django-rest-framework 基础三 认证.权限和频率 1. 认证 1.1 登录接口 1.2 认证 2. 权限 ...
随机推荐
- Android可以拖动位置的ListVeiw
参考网址: 1.https://github.com/bauerca/drag-sort-listview 2.http://www.tuicool.com/articles/jyA3MrU
- RHCE6.4 rpm 安装gcc
先将gcc的iso里的Packages拷贝到根目录下,方便以后使用,再找gcc的rpm包安装: 网上说有以下依赖,需要按照一下顺序安装: rpm -ivh cpp*****.rpm rpm -ivh ...
- Flex中单选按钮控制表格中的列的增加或减少
1.问题背景 单选按钮有"苹果"和"香蕉"两个,表格中的列有星期.苹果.香蕉和苹果比率,选择了"苹果"单选按钮,表格显示星期.苹果和苹果比率 ...
- Struts2(三) 配置struts.xml的提示(在不联网的情况下)
开发过程中如果可以上网,struts.xml 会自动缓存dtd,提供提示功能.如果不能联网需要我们配置本地dtd,这样才能让struts2 产生提示 1.首先,在EClipse中依次点击工具栏中的wi ...
- MvcHtmlString解决MVC中从后台返回HTML代码被编码问题
(1) 要得到的效果 <a class="easyui-linkbutton" data-options="iconCls:'icon-add'" id= ...
- 主流nosql数据库对比
目前开源的NOSQL数据库有,Redis,Tokyo Cabinet,Cassandra,Voldemort,MongoDB,Dynomite,HBase,CouchDB,Hypertable, Ri ...
- Keras官方中文文档:关于Keras模型
关于Keras模型 Keras有两种类型的模型,序贯模型(Sequential)和函数式模型(Model),函数式模型应用更为广泛,序贯模型是函数式模型的一种特殊情况. 两类模型有一些方法是相同的: ...
- [Luogu2617]Dynamic Ranking
题面戳这 类似算法总结 1.静态整体Kth 滑稽吧...sort一遍就好了. 时间复杂度\(O(nlogn)\) 空间复杂度\(O(n)\) 2.动态整体Kth 离散化后开一棵权值线段树,每个位置的值 ...
- 【SPOJ】Distinct Substrings/New Distinct Substrings(后缀数组)
[SPOJ]Distinct Substrings/New Distinct Substrings(后缀数组) 题面 Vjudge1 Vjudge2 题解 要求的是串的不同的子串个数 两道一模一样的题 ...
- 接收JSON类型转成对象
写个小例子吧: public String getJsonTest(String jsonString){} 参数是json 参数长这样 ===> { 'puser' : {'id' : ' ...