【Shiro】 权限

Metadata

title: 【Shiro】 权限
date: 2023-01-20 10:16
tags:
  - 行动阶段/完成
  - 主题场景/组件
  - 笔记空间/KnowladgeSpace/ProgramSpace/ModuleSpace
  - 细化主题/Module/Shiro/基础
categories:
  - Shiro
keywords:
  - Shiro
description: 【Shiro】 权限

【Shiro】 权限

Shiro 将 Permission 定义为定义明确行为或动作的语句。它是应用程序中原始功能的声明,仅此而已。权限是安全策略中最低级别的构造,它们仅明确定义应用程序可以执行的“操作”。

他们根本没有描述“谁”能够执行这些操作。
一些权限示例:

  • 打开文件
  • 查看 ‘/user/list’ 网页
  • 打印文件
  • 删除“jsmith”用户

定义允许“谁”(用户)做“什么”(权限)是一种以某种方式为用户分配权限的练习。这始终由应用程序的数据模型完成,并且可能因应用程序而异。

例如,可以将权限分组到角色中,并且该角色可以与一个或多个用户对象相关联。或者某些应用程序可以有一组用户,并且可以为一个组分配一个角色,这通过传递关联意味着该组中的所有用户都被隐式授予角色中的权限。

授予用户权限的方式有很多变化 - 应用程序根据应用程序要求确定如何对其进行建模。

通配符权限

上面的权限示例,“打开文件”,“查看’用户/列表’网页”等都是有效的权限语句。但是,要解释这些自然语言字符串并确定用户是否在计算上非常困难是否允许执行该行为。

因此,为了启用易于处理但仍可读的权限语句,Shiro 提供了强大而直观的权限语法,我们称之为 WildcardPermission。

简单用法

假设您要保护对公司打印机的访问,以便一些人可以打印到特定打印机,而其他人可以查询当前队列中的作业。

一种非常简单的方法是授予用户“queryPrinter”权限。然后您可以通过调用来检查用户是否具有queryPrinter权限:

subject.isPermitted("queryPrinter")

这(大部分)等同于

subject.isPermitted(new WildcardPermission("queryPrinter"))

但稍后会详细介绍。

简单的权限字符串可能适用于简单的应用程序,但它需要您具有“printPrinter”、“queryPrinter”、“managePrinter”等权限。您还可以使用通配符授予用户”*“权限(授予此权限构造其名称),这意味着他们拥有整个应用程序的所有权限。

但是使用这种方法没有办法只说用户拥有“所有打印机权限”。因此,通配符权限支持多级权限。

主体

通配符权限支持多层次或多部分的概念。例如,您可以通过授予用户权限来重构前面的简单示例

printer:query

此示例中的冒号是一个特殊字符,用于分隔权限字符串中的下一部分。

在此示例中,第一部分是正在操作的域 ( printer),第二部分是query正在执行的操作 ( )。上面的其他示例将更改为:

printer:print
printer:manage

可以使用的部件数量没有限制,因此在您的应用程序中可以使用的方式取决于您的想象力。

多个值

每个部分可以包含多个值。因此,与其同时授予用户“printer:print”和“printer:query”权限,您可以简单地授予他们一个:

printer:print,query

这使他们有能力print和query打印机。由于他们被授予这两种操作,您可以检查用户是否能够通过调用查询打印机:

subject.isPermitted("printer:query")

这将返回true

所有值

如果您想授予用户特定部分的所有值怎么办?这样做比必须手动列出每个值更方便。同样,基于通配符,我们可以做到这一点。如果printer域有 3 个可能的操作(query、print和manage),则:

printer:query,print,manage

简单地变成这样:

printer:*

然后,对“printer:XXX”的任何权限检查都将返回true。以这种方式使用通配符比显式列出操作更好,因为如果您稍后向应用程序添加新操作,则不需要更新在该部分使用通配符的权限。

最后,还可以在通配符权限字符串的任何部分使用通配符标记。例如,如果您想授予用户跨所有域(不仅仅是打印机)的“查看”操作,您可以授予此权限:

*:view

然后对“foo:view”的任何权限检查都会返回true

实例级访问控制

通配符权限的另一个常见用法是建模实例级访问控制列表。在这个场景中,您使用了三个部分——第一个是域,第二个是操作,第三个是被操作的实例。

所以例如你可以有

printer:query:lp7200
printer:print:epsoncolor

第一个query使用printerID定义行为lp7200。第二个权限定义了printIDprinter的行为epsoncolor。如果您将这些权限授予用户,那么他们就可以在特定实例上执行特定行为。然后你可以做一个签入代码:

if ( SecurityUtils.getSubject().isPermitted("printer:query:lp7200") {
    // Return the current jobs on printer lp7200 }
}

这是表达权限的一种极其强大的方式。但同样,必须为所有打印机定义多个实例 ID 并不能很好地扩展,尤其是在将新打印机添加到系统时。您可以改用通配符:

printer:print:*

这确实具有扩展性,因为它也涵盖了任何新打印机。您甚至可以允许访问所有打印机上的所有操作:

printer:*:*

或一台打印机上的所有操作:

printer:*:lp7200

甚至具体行动:

printer:query,print:lp7200