授权即访问控制,它将判断用户在应用程序中对资源是否拥有相应的访问权限。

如,判断一个用户有查看页面的权限,编辑数据的权限,拥有某一按钮的权限等等。

一、用户权限模型

为实现一个较为灵活的用户权限数据模型,通常把用户信息单独用一个实体表示,用户权限信息用两个实体表示。

  1. 用户信息用 LoginAccount 表示,最简单的用户信息可能只包含用户名 loginName 及密码 password 两个属性。实际应用中可能会包含用户是否被禁用,用户信息是否过期等信息。
  2. 用户权限信息用 Role 与 Permission 表示,Role 与 Permission 之间构成多对多关系。Permission 可以理解为对一个资源的操作,Role 可以简单理解为 Permission 的集合。
  3. 用户信息与 Role 之间构成多对多关系。表示同一个用户可以拥有多个 Role,一个 Role 可以被多个用户所拥有。

权限声明及粒度

Shiro权限声明通常是使用以冒号分隔的表达式。就像前文所讲,一个权限表达式可以清晰的指定资源类型,允许的操作。同时,Shiro权限表达式支持简单的通配符,可以更加灵活的进行权限设置。

下面以实例来说明权限表达式。

可查询用户数据

User:view

可查询或编辑用户数据

User:view,edit

可对用户数据进行所有操作

User:*或 user

可编辑id为123的用户数据

User:edit:123

授权处理过程

认证通过后接受 Shiro 授权检查,授权验证时,需要判断当前角色是否拥有该权限。

只有授权通过,才可以访问受保护 URL 对应的资源,否则跳转到“未经授权页面”。

如果我们自定义Realm实现,比如我后面的例子中,自定义了ShiroDbRealm类,当访问被@RequiresPermissions注解的方法时,会先执行ShiroDbRealm.doGetAuthorizationInfo()进行授权。

  1. <span style="font-size:18px">@Controller
  2. @RequestMapping(value = "/user")
  3. public class UserController {
  4. @Resource(name="userService")
  5. private IUserService userService;
  6. /**
  7. * 测试权限
  8. * 只有拥有 user:create权限,才能进行注册
  9. * @param user
  10. * @return
  11. */
  12. @RequestMapping(value = "/register")
  13. @ResponseBody
  14. @RequiresPermissions("user:create")
  15. public boolean register(User user){
  16. return userService.register(user);
  17. }</span>

二、授权实现

Shiro支持三种方式实现授权过程:

  • 编码实现
  • 注解实现
  • JSP Taglig实现

1、基于编码的授权实现

1、基于权限对象的实现

创建org.apache.shiro.authz.Permission的实例,将该实例对象作为参数传递给Subject.isPermitted()进行验证。

  1. Permission printPermission = new PrinterPermission("laserjet4400n", "print");
  2. Subject currentUser = SecurityUtils.getSubject();
  3. if (currentUser.isPermitted(printPermission)) {
  4. //show the Print button
  5. } else {
  6. //don't show the button?  Grey it out?
  7. }

2基于字符串的实现

相比笨重的基于对象的实现方式,基于字符串的实现便显得更加简洁。

  1. Subject currentUser = SecurityUtils.getSubject();
  2. if (currentUser.isPermitted("printer:print:laserjet4400n")) {
  3. //show the Print button
  4. } else {
  5. //don't show the button?  Grey it out?
  6. }

使用冒号分隔的权限表达式是org.apache.shiro.authz.permission.WildcardPermission默认支持的实现方式。

这里分别代表了资源类型:操作:资源ID

2、基于注解的授权实现

Shiro注解支持AspectJ、Spring、Google-Guice等,可根据应用进行不同的配置。

相关的注解:

@RequiresAuthentication

可以用户类/属性/方法,用于表明当前用户需是经过认证的用户。

  1. @RequiresAuthentication
  2. public void updateAccount(Account userAccount) {
  3. //this method will only be invoked by a
  4. //Subject that is guaranteed authenticated
  5. ...
  6. }

@RequiresPermissions

当前用户需拥有制定权限

  1. @RequiresPermissions("account:create")
  2. public void createAccount(Account account) {
  3. //this method will only be invoked by a Subject
  4. //that is permitted to create an account
  5. ...
  6. }

3、基于JSP TAG的授权实现

Shiro提供了一套JSP标签库来实现页面级的授权控制。

在使用Shiro标签库前,首先需要在JSP引入shiro标签:

  1. <%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

hasRole标签

验证当前用户是否属于该角色

  1. <shiro:hasRole name="administrator">
  2. <a href="admin.jsp">Administer the system</a>
  3. </shiro:hasRole>

hasPermission标签

验证当前用户是否拥有制定权限

  1. <shiro:hasPermission name="user:create">
  2. <a href="createUser.jsp">Create a new User</a>
  3. </shiro:hasPermission>

三、Shiro授权的内部处理机制

1、在应用程序中调用授权验证方法(Subject的isPermitted*或hasRole*等)

2、Sbuject会委托应用程序设置的securityManager实例调用相应的isPermitted*或hasRole*方法。

3、接下来SecurityManager会委托内置的Authorizer的实例(默认是ModularRealmAuthorizer类的实例,类似认证实例)调用相应的授权方法。

4、每一个Realm将检查是否实现了相同的Authorizer 接口。然后,将调用Reaml自己的相应的授权验证方法。

四、授权代码

UserController:处理用户登录后的请求(注册)

  1. package org.shiro.demo.controller;
  2. import javax.annotation.Resource;
  3. import org.apache.shiro.authz.annotation.RequiresPermissions;
  4. import org.apache.shiro.authz.annotation.RequiresRoles;
  5. import org.shiro.demo.entity.User;
  6. import org.shiro.demo.service.IUserService;
  7. import org.springframework.stereotype.Controller;
  8. import org.springframework.web.bind.annotation.RequestMapping;
  9. import org.springframework.web.bind.annotation.ResponseBody;
  10. @Controller
  11. @RequestMapping(value = "/user")
  12. public class UserController {
  13. @Resource(name="userService")
  14. private IUserService userService;
  15. /**
  16. * 测试权限
  17. * 只有拥有 user:create 权限,才能进行注册
  18. * @param user
  19. * @return
  20. */
  21. @RequestMapping(value = "/register")
  22. @ResponseBody
  23. @RequiresPermissions("user:create")
  24. public boolean register(User user){
  25. return userService.register(user);
  26. }
  27. /**
  28. * 测试角色
  29. * 只有拥有 administrator 角色,才能跳转到register页面
  30. * @return
  31. */
  32. @RequestMapping(value = "/toRegister")
  33. @RequiresRoles("administrator")
  34. public String toRegister(){
  35. return "/system/user/register";
  36. }
  37. }

ShiroDbRealm:自定义的指定Shiro验证用户授权的类

    1. <span style="font-size:18px">packageorg.shiro.demo.service.realm;
    2. importjava.util.ArrayList;
    3. importjava.util.List;
    4. importjavax.annotation.Resource;
    5. importorg.apache.commons.lang.StringUtils;
    6. importorg.apache.shiro.authc.AuthenticationException;
    7. importorg.apache.shiro.authc.AuthenticationInfo;
    8. importorg.apache.shiro.authc.AuthenticationToken;
    9. importorg.apache.shiro.authc.SimpleAuthenticationInfo;
    10. importorg.apache.shiro.authc.UsernamePasswordToken;
    11. importorg.apache.shiro.authz.AuthorizationException;
    12. importorg.apache.shiro.authz.AuthorizationInfo;
    13. importorg.apache.shiro.authz.SimpleAuthorizationInfo;
    14. importorg.apache.shiro.realm.AuthorizingRealm;
    15. importorg.apache.shiro.subject.PrincipalCollection;
    16. importorg.shiro.demo.entity.Permission;
    17. importorg.shiro.demo.entity.Role;
    18. importorg.shiro.demo.entity.User;
    19. importorg.shiro.demo.service.IUserService;
    20. /**
    21. * 自定义的指定Shiro验证用户登录的类
    22. * @author TCH
    23. *
    24. */
    25. publicclass ShiroDbRealm extends AuthorizingRealm{
    26. //@Resource(name="userService")
    27. privateIUserService userService;
    28. publicvoid setUserService(IUserService userService) {
    29. this.userService= userService;
    30. }
    31. /**
    32. * 为当前登录的Subject授予角色和权限
    33. * @see 经测试:本例中该方法的调用时机为需授权资源被访问时
    34. * @see经测试:并且每次访问需授权资源时都会执行该方法中的逻辑,这表明本例未启用AuthorizationCache
    35. * @seeweb层可以有shiro的缓存,dao层可以配有hibernate的缓存(后面介绍)
    36. */
    37. protectedAuthorizationInfo doGetAuthorizationInfo(
    38. PrincipalCollectionprincipals) {
    39. //获取当前登录的用户名,等价于(String)principals.fromRealm(this.getName()).iterator().next()
    40. Stringaccount = (String) super.getAvailablePrincipal(principals);
    41. List<String>roles = new ArrayList<String>();
    42. List<String>permissions = new ArrayList<String>();
    43. //从数据库中获取当前登录用户的详细信息
    44. Useruser = userService.getByAccount(account);
    45. if(user!= null){
    46. //实体类User中包含有用户角色的实体类信息
    47. if(user.getRoles() != null && user.getRoles().size() > 0) {
    48. //获取当前登录用户的角色
    49. for(Role role : user.getRoles()) {
    50. roles.add(role.getName());
    51. //实体类Role中包含有角色权限的实体类信息
    52. if(role.getPmss() != null && role.getPmss().size() > 0) {
    53. //获取权限
    54. for(Permission pmss : role.getPmss()) {
    55. if(!StringUtils.isEmpty(pmss.getPermission())){
    56. permissions.add(pmss.getPermission());
    57. }
    58. }
    59. }
    60. }
    61. }
    62. }else{
    63. thrownew AuthorizationException();
    64. }
    65. //为当前用户设置角色和权限
    66. SimpleAuthorizationInfoinfo = new SimpleAuthorizationInfo();
    67. info.addRoles(roles);
    68. info.addStringPermissions(permissions);
    69. returninfo;
    70. }
    71. }</span>

shiro中基于注解实现的权限认证过程的更多相关文章

  1. 将 Shiro 作为应用的权限基础 三:基于注解实现的授权认证过程

    授权即访问控制,它将判断用户在应用程序中对资源是否拥有相应的访问权限. 如,判断一个用户有查看页面的权限,编辑数据的权限,拥有某一按钮的权限等等. 一.用户权限模型 为实现一个较为灵活的用户权限数据模 ...

  2. Shiro入门之二 --------基于注解方式的权限控制与Ehcache缓存

    一  基于注解方式的权限控制 首先, 在spring配置文件applicationContext.xml中配置自动代理和切面 <!-- 8配置自动代理 -->    <bean cl ...

  3. Spring+Shiro搭建基于Redis的分布式权限系统(有实例)

    摘要: 简单介绍使用Spring+Shiro搭建基于Redis的分布式权限系统. 这篇主要介绍Shiro如何与redis结合搭建分布式权限系统,至于如何使用和配置Shiro就不多说了.完整实例下载地址 ...

  4. Struts2中基于Annotation的细粒度权限控制

    Struts2中基于Annotation的细粒度权限控制 2009-10-19 14:25:53|  分类: Struts2 |  标签: |字号大中小 订阅     权限控制是保护系统安全运行很重要 ...

  5. 登陆模块,这个是很重要的模块,有shiro和spring security专门的权限认证框架

    登陆模块,这个是很重要的模块,有shiro和spring security专门的权限认证框架

  6. spring中基于注解使用AOP

    本文内容:spring中如何使用注解实现面向切面编程,以及如何使用自定义注解. 一个场景 比如用户登录,每个请求发起之前都会判断用户是否登录,如果每个请求都去判断一次,那就重复地做了很多事情,只要是有 ...

  7. Spring MVC中基于注解的 Controller

         终于来到了基于注解的 Spring MVC 了.之前我们所讲到的 handler,需要根据 url 并通过 HandlerMapping 来映射出相应的 handler 并调用相应的方法以响 ...

  8. spring中基于注解使用ehcache

    继续上篇,这篇介绍服务层缓存,基于注解的方式使用ehcache 注解的标签主要有4个:@Cacheable.@CacheEvict.@CachePut.@Caching,他们的用法是: @Cachea ...

  9. Spring中基于注解的IOC(二):案例与总结

    2.Spring的IOC案例 创建maven项目 导入依赖 pom.xml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ...

随机推荐

  1. MQ--API总结

    研究MQ很长时间了, 每个类,方法,都查了很长时间,在此总结一下! Java编写访问MQ的程序 1.MQQueueManager―――队列管理器访问类  常用方法: public MQQueueMan ...

  2. MVVM的核心:双向绑定

    MVVM 模式将 Presenter 改名为 ViewModel,基本上与 MVP 模式完全一致. 唯一的区别是,它采用双向绑定(data-binding):View的变动,自动反映在 ViewMod ...

  3. 「CF375D Tree and Queries」

    题目 \(dsu\ on\ tree\)的板子题了 \(dsu\ on\ tree\)本质上一种优秀通过轻重链剖分优化到\(O(nlogn)\)的暴力 一般用来解决没有修改的允许离线的子树查询问题 首 ...

  4. CMD命令不完全版

    cmd命令: 感谢GSC大佬提供命令 clearmgr : 清理垃圾 taskmgr : 任务管理器 eventvwr : 事件管理器 shutdown -s -t 10 : 关机 shutdown ...

  5. 理解JavaScript原始类型和引用类型

    原始类型 我们知道类型(type)定义为值的一个集合,所以每种原始类型定义了它包含的值的范围及其字面量表示形式.一共有5 种原始类型(primitive type),即 Undefined.Null. ...

  6. 如何指定安装webpack

    在此我要推荐webpack简易学习教程:https://www.runoob.com/w3cnote/webpack-tutorial.html 大家可以参考这个菜鸟教程,但是这个菜鸟教程有其局限性, ...

  7. px,rem,em的区别

    PX特点 1. IE无法调整那些使用px作为单位的字体大小: 2. 国外的大部分网站能够调整的原因在于其使用了em或rem作为字体单位: 3. Firefox能够调整px和em,rem,但是96%以上 ...

  8. enmu枚举类型

    在实际问题中,有些变量的取值被限定在一个有限的范围内.例如,一个星期内只有七天,一年只有十二个月,一个班每周有六门课程等等.如果把这些量说明为整型,字符型或其它类型显然是不妥当的.为此,C语言提供了一 ...

  9. Sublime text3学习小记(macOS系统下的安装使用)

    [注:以下内容参考https://blog.csdn.net/stilling2006/article/details/54376743] 一.认识Sublime text 1.一款跨平台代码编辑器, ...

  10. 如何在github上实现预览

    这个问题在网络上有很多答案,但是真正能解决的寥寥无几!接下来我就来尝试一下网络上疯传的几种方法.准备好了吗?我要开车了!!! PS:以下实验上传到github的demo采取导入本地css,js和网络上 ...