Apache Shiro 的 Java 授权指南

授权或访问控制是指定对资源的访问权限的功能。换句话说,* who 可以访问 what *。

授权检查的示例包括:是否允许用户查看此网页,编辑此数据,查看此按钮或打印到该打印机?这些都是决定用户有权访问的内容的决定。

授权要素

授权在 Shiro 中涉及了三个核心元素,即权限,角色和用户。

Permissions Defined

权限是安全策略的最基本的级别,它们是功能的声明。权限代表可以在您的应用程序中执行的操作。格式正确的权限描述了资源类型以及与这些资源进行交互时可以执行的操作。你能吗?你能文件吗?您可以删除**Client 记录吗?您可以按钮*吗?

数据相关资源的常见操作是创建,读取,更新和删除,通常称为 CRUD。

重要的是要理解权限不知道可以执行哪些操作的权限,它们只是可以执行的操作的声明。

权限级别

首先,权限指定对资源(门,文件,Client 记录等)的操作(打开,读取,删除等)。在 Shiro 中,您可以定义任意深度的权限。以下是按粒度 Sequences 列出的一些常见权限级别。

  • 资源级别-这是最广泛,最容易构建的资源。用户可以编辑 Client 记录或开门。指定了资源,但未指定该资源的特定实例。

  • 实例级别-权限指定资源的实例。用户可以编辑 IBM 的 Client 记录或打开厨房门。

  • 属性级别-权限现在指定实例或资源的属性。用户可以编辑 IBMClient 记录上的地址。

有关权限的更多信息,请查看Permissions Documentation

Roles Defined

在授权的上下文中,角色实际上是权限的集合,用于简化权限和用户的 Management。因此,可以为用户分配角色,而不是直接为他们分配权限,这会因更大的用户群和更复杂的应用程序而变得复杂。因此,例如,银行应用程序可能具有Management 员角色或银行柜员角色。

您需要了解两种角色,并且 Shiro 将支持这两种角色。

Implicit Roles

大多数人将角色视为我们定义为隐式角色的角色,其中您的应用程序隐含一组权限,因为用户具有特定的角色,而不是角色被显式分配权限或您的应用程序检查这些权限。代码中的角色检查通常反映了隐式角色。您可以查看患者数据,因为您具有* administrator *角色。您可以创建帐户,因为您具有“银行出纳员”角色。这些名称存在的事实与软件的实际功能没有关联。大多数人都以这种方式使用角色。这是最简单的方法,但是除了最简单的应用程序之外,它可能为其他所有程序带来很多维护和 Management 问题。

Explicit Roles

显式角色具有“显式”分配的权限,因此是“显式”的权限集合。代码中的权限检查反映了显式角色。您可以查看患者数据,因为您作为Management 员角色的一部分具有查看患者数据权限。您可以创建帐户,因为您具有创建帐户权限,属于银行柜员角色。您可以执行这些操作,不是因为有一些基于字符串的隐式角色名称,而是因为相应的权限已显式分配给您的角色。

显式角色的最大好处是易于 Management,并减少了应用程序维护。如果您需要添加,删除或更改角色,则无需触摸源代码即可完成。在 Shiro 中,您还可以在运行时动态添加,删除或更改角色,并且您的授权检查将始终具有最新值。这意味着您不必强制用户注销并重新登录即可获取其新权限。

Users Defined

用户是应用程序的“谁”。但是,在 Shiro 中,用户的概念实际上是Subject实例。我们使用“主题”一词代替“用户”一词,因为用户通常暗指一个人,而在 Shiro 中,“主题”可以是与您的应用程序交互的任何东西-无论是人类还是服务。

允许用户通过与角色或直接权限的关联在您的应用程序中执行某些操作。因此,您可以打开 Client 记录,因为您已经通过分配的角色或直接的权限分配获得了“打开 Client 记录”权限。

有关用户(又称主题)的更多信息,请查看Subject Documentation

Note

最终,您的Realm实现是与数据源(RDBMS,LDAP 等)进行通信的对象。因此,您的境界将告诉 Shiro 是否存在角色或权限。您可以完全控制授权模型的工作方式。

如何使用 Shiro 在 Java 中执行授权

Shiro 中的授权可以通过四种方式处理。

  • 以编程方式-您可以使用ifelse块之类的结构在 Java 代码中执行授权检查。

  • JDKComments-您可以将授权 Comments 附加到 Java 方法

  • JSP/GSP TagLibs-您可以根据角色和权限控制 jsp 或 gsp 页面的输出

Programmatic Authorization

在 Java 代码中以编程方式检查权限和角色是处理授权的传统方法。在 Shiro 中执行权限检查或角色检查的方法如下。

Role Check

这是如何在应用程序中以编程方式进行角色检查的示例。我们要检查用户是否具有* administrator *角色,如果有,则将显示一个特殊按钮,否则将不显示它。

首先,我们可以访问当前用户Subject。然后,我们将* adminstrator *传递给 Subject 的.hasRole()方法。它将返回TRUEFALSE

//get the current Subject 
Subject currentUser = SecurityUtils.getSubject();

if (currentUser.hasRole("administrator")) {
    //show a special button‏
} else {
    //don't show the button?)‏
}

现在,基于角色的检查可以快速,轻松地实现,但它有一个主要缺点。它是隐式的。

如果您以后只想添加,删除或重新定义角色怎么办?您将不得不打开源代码并更改所有角色检查,以反映安全模型中的更改。您必须关闭应用程序,打开代码,对其进行测试,然后每次重新启动。

在非常简单的应用程序中,这可能已经足够了,但对于大型应用程序而言,这可能是整个应用程序生命周期内的主要问题,并为您的软件带来大量维护成本。

Permission Check

这是如何通过权限进行安全检查的示例。我们要检查用户是否有权打印到 laserjet3000n,如果这样做,我们将显示一个打印按钮,否则将不显示它。这是实例级别权限或实例级别授权的示例。

同样,首先您可以访问当前用户Subject。然后,构造一个Permission对象或一个实例,该对象代表对资源的操作。在这种情况下,实例名为printerPermission,资源为* laserjet3000n ,操作为 print *。然后,我们将printerPermission传递给主题的.isPermitted()方法。它将返回 true 或 false。

Subject currentUser = SecurityUtils.getSubject();

Permission printPermission = new PrinterPermission("laserjet3000n","print");

If (currentUser.isPermitted(printPermission)) {
    //do one thing (show the print button?)‏
} else {
    //don't show the button?
}

权限检查(基于字符串)

您还可以使用简单的字符串而不是权限类进行权限检查。

因此,如果您不想实现我们的permission interface,则只需传入一个 String。在此示例中,我们向.isPermitted()方法传递了一个字符串printer:print:LaserJet4400n

String perm = "printer:print:laserjet4400n";

if(currentUser.isPermitted(perm)){
    //show the print button?
} else {
    //don't show the button?
}

只要您的Realm知道如何使用它,就可以按照您想要的方式构造权限字符串。在此示例中,我们使用 Shiro 的可选权限语法WildCardPermissions。 WildCardPermissions 功能强大且直观。如果您想了解更多有关它们的信息,请查看Permissions Documentation

使用基于字符串的权限检查,您将获得与之前示例相同的功能。好处是您不必强制实现权限接口,而是可以通过简单的字符串构造权限。缺点是您没有类型安全性,并且如果您需要超出其表示范围的更复杂的权限功能,则需要基于权限接口实现自己的权限对象。

Annotation Authorization

如果您不想执行代码级授权检查,则也可以使用 JavaComments。 Shiro 提供了许多Java annotations,可让您 Comments 方法。

启用 Comments 支持

在使用 Java 注解之前,您需要在应用程序中启用 AOP 支持。有许多不同的 AOP 框架,因此,不幸的是,没有在应用程序中启用 AOP 的标准方法。

对于 AspectJ,您可以查看我们的AspectJ 示例应用程序

对于 Spring,您可以查看我们的Spring Integration文档。

对于 Guice,您可以查看我们的Guice Integration文档。

Permission Check

在此示例中,我们要检查用户是否具有account:create权限,然后才能调用openAccount方法。如果是这样,则按预期方式调用该方法,否则,将引发异常。

与程序检查一样,您可以在此 Comments 中使用Permission对象或简单的字符串方法。

//Will throw an AuthorizationException if none
//of the caller's roles imply the Account
//'create' permission
@RequiresPermissions("account:create")‏
public void openAccount( Account acct ) {
    //create the account
}

Role Check

在此示例中,我们希望在用户可以调用openAccount方法之前检查用户是否具有teller角色。如果是这样,则按预期方式调用该方法,否则,将引发异常。

//Throws an AuthorizationException if the caller
//doesn't have the 'teller' role:
@RequiresRoles( "teller" )
public void openAccount( Account acct ) {
    //do something in here that only a teller
    //should do
}

JSP TagLib 授权

对于基于 JSP/GSP 的 Web 应用程序,Shiro 还提供了tag library供您使用。

在此示例中,我们将向具有* users:manage *权限的用户显示指向“Management 用户”页面的链接。如果他们没有许可,那么我们将向他们显示一个好消息。

首先,我们需要将 Shiro taglib 添加到我们的 Web 应用程序中。接下来,我们添加<shiro:hasPermission>标签并选中* users:manage 。如果用户具有我们要检查的权限,我们将在<shiro:hasPermission>标记内放置要执行的代码。如果我们要在用户缺乏权限的情况下采取措施,那么我们还需要添加<shiro:lacksPermission>标签,再次检查 users:manage *。如果用户缺乏权限,我们要执行的任何代码都必须放在<shiro:lacksPermission>标记内。

<%@ taglib prefix="shiro" uri=http://shiro.apache.org/tags %>
<html>
<body>
    <shiro:hasPermission name="users:manage">
        <a href="manageUsers.jsp">
            Click here to manage users
        </a>
    </shiro:hasPermission>
    <shiro:lacksPermission name="users:manage">
        No user management for you!
    </shiro:lacksPermission>
</body>
</html>

当然,还有用于检查角色以及其他用户数据和状态的标签。

有关 JSP/GSP 标签的更多信息,请查阅JSP 标签库,有关将应用程序集成到 Web 应用程序中的更多信息,请阅读Web 集成文档

Caching Authorization

TBD

协助处理文档

尽管我们希望该文档对您使用 Apache Shiro 所做的工作有所帮助,但社区一直在不断改进和扩展文档。如果您想为 Shiro 项目提供帮助,请考虑在需要的地方更正,扩展或添加文档。您提供的每一点帮助都会扩大社区,进而改善 Shiro。

提交文档的最简单方法是通过单击下面的Edit链接提交请求请求,然后将其发送到User Forum用户邮件列表