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类,当访问被@RequiresPermissions注解的方法时,会先执行ShiroDbRealm.doGetAuthorizationInfo()进行授权。
- <span style="font-size:18px">@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);
- }</span>
二、授权实现
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标签:
- <%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
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验证用户授权的类
- <span style="font-size:18px">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;
- }
- }</span>
shiro中基于注解实现的权限认证过程的更多相关文章
- 将 Shiro 作为应用的权限基础 三:基于注解实现的授权认证过程
授权即访问控制,它将判断用户在应用程序中对资源是否拥有相应的访问权限. 如,判断一个用户有查看页面的权限,编辑数据的权限,拥有某一按钮的权限等等. 一.用户权限模型 为实现一个较为灵活的用户权限数据模 ...
- Shiro入门之二 --------基于注解方式的权限控制与Ehcache缓存
一 基于注解方式的权限控制 首先, 在spring配置文件applicationContext.xml中配置自动代理和切面 <!-- 8配置自动代理 --> <bean cl ...
- Spring+Shiro搭建基于Redis的分布式权限系统(有实例)
摘要: 简单介绍使用Spring+Shiro搭建基于Redis的分布式权限系统. 这篇主要介绍Shiro如何与redis结合搭建分布式权限系统,至于如何使用和配置Shiro就不多说了.完整实例下载地址 ...
- Struts2中基于Annotation的细粒度权限控制
Struts2中基于Annotation的细粒度权限控制 2009-10-19 14:25:53| 分类: Struts2 | 标签: |字号大中小 订阅 权限控制是保护系统安全运行很重要 ...
- 登陆模块,这个是很重要的模块,有shiro和spring security专门的权限认证框架
登陆模块,这个是很重要的模块,有shiro和spring security专门的权限认证框架
- spring中基于注解使用AOP
本文内容:spring中如何使用注解实现面向切面编程,以及如何使用自定义注解. 一个场景 比如用户登录,每个请求发起之前都会判断用户是否登录,如果每个请求都去判断一次,那就重复地做了很多事情,只要是有 ...
- Spring MVC中基于注解的 Controller
终于来到了基于注解的 Spring MVC 了.之前我们所讲到的 handler,需要根据 url 并通过 HandlerMapping 来映射出相应的 handler 并调用相应的方法以响 ...
- spring中基于注解使用ehcache
继续上篇,这篇介绍服务层缓存,基于注解的方式使用ehcache 注解的标签主要有4个:@Cacheable.@CacheEvict.@CachePut.@Caching,他们的用法是: @Cachea ...
- Spring中基于注解的IOC(二):案例与总结
2.Spring的IOC案例 创建maven项目 导入依赖 pom.xml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ...
随机推荐
- 【深入理解JAVA虚拟机】第三部分.虚拟机执行子系统.2.虚拟机类加载机制
1.概述 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验. 转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 2.类加载顺序 类从被加载到虚拟 ...
- [原]Ping azure
最近在azure上开了一个虚拟机(大陆世纪互联的),发现竟然不能ping虚拟机! 查了一下资料发现原来azure不支持被ping这个功能(貌似是不开放ICMP-in这个协议),有些用户跟客服问过这个问 ...
- 上海大智慧某站未授权访问&SQL注入
详细说明: 注入:禁用JS,http://dzh.com.cn/admin/userlist.phphttp://dzh.com.cn/admin/editUser.php?username=test ...
- MySQL的存储函数(自定义函数)的定义和使用方法
存储函数 什么是存储函数: 封装一段sql代码,完成一种特定的功能,返回结果. 存储函数的语法: create function 函数([函数参数[,….]]) Returns 返回类型 Begin ...
- 20140316 曼联VS利物浦,罗杰斯的小九九,当4312对上4231
一.预测的阵式!? 赛前看fourfourtwo,Whoscored的首发预测,楼主立刻意淫了阵式图,并且大言不惭在微博贴了当晚的热战区域(上图的左侧),并疑惑着,格伦·囧森打左后卫,那这……显然是逼 ...
- sublime text html5开发学习 插件篇记录
1.第一步先按照 Package Control,具体步骤自行百度,Google. 2. view in browser 默认的快捷键应该是这样的,我用的是IE浏览器.所以ctrl+alt+i 即可让 ...
- RabbitMQ Windows环境搭建
1.0 RabbitMQ是用Erlang语言编写,因此安装RabbitMQ,首先要安装Erlang. Erlang的官网:http://www.erlang.org/ 文件:otp_win64_19. ...
- 开源项目之kisso
kisso开源项目:https://gitee.com/baomidou/kisso 一.简介 kisso = cookie sso 基于 Cookie 的 SSO 中间件,它是一把快速开发 ja ...
- PAT——1017. A除以B
本题要求计算A/B,其中A是不超过1000位的正整数,B是1位正整数.你需要输出商数Q和余数R,使得A = B * Q + R成立. 输入格式: 输入在1行中依次给出A和B,中间以1空格分隔. 输出格 ...
- java.sql.date和java.util.date的区别和转换
不同点:java.util.Date是在除了SQL语句的情况下面使用的.java.sql.Date是针对SQL语句使用的,它只包含日期而没有时间部分java.util.Date 是 java.sql. ...