在Web应用程序中实现基于角色的访问控制

RBAC是一种访问控制模型,在该模型中,访问系统中的资源或操作的能力与权限(或策略)相关联,并且这些权限中的每一个都与一个或多个角色相关联。系统中的每个用户都有一个或多个角色,因此拥有与这些角色相关联的所有权限。这种分层结构非常直观,非常适合管理各种应用程序中的用户访问,如SaaS和企业软件、电子商务网站、公司内部应用

hefengbao 发布于 2023.03.26 ,最后更新于 2023.09.18

访问控制是允许(或不允许)用户访问软件系统中的特定资源或操作的过程。例如,只允许某些用户访问网站上的内部管理页面,或者只允许付费用户访问高级功能。有许多实现访问控制的方法,但基于角色的访问控制(RBAC)是最流行和最广泛使用的方法之一。在本指南中,我们将介绍实现RBAC的标准方法,并讨论在API和web应用程序中实现访问控制的一些最佳实践。

概述

RBAC是一种访问控制模型,在该模型中,访问系统中的资源或操作的能力与权限(或策略)相关联,并且这些权限中的每一个都与一个或多个角色相关联。系统中的每个用户都有一个或多个角色,因此拥有与这些角色相关联的所有权限。这种分层结构非常直观,非常适合管理各种应用程序中的用户访问,如SaaS和企业软件、电子商务网站、公司内部应用程序等。

由于访问控制(尤其是RBAC)从根本上来说是一个关系问题,因此使用PostgreSQL或MySQL这样的关系数据库来实现它是有意义的。我们将在本指南中使用SQL分解数据模型。

用户(Users)

在做任何其他事情之前,我们需要跟踪应用程序中的用户。出于本指南的目的,我们只需要为系统中的每个用户提供一个唯一的id。稍后将使用此id将用户与角色关联起来。大多数应用程序还将存储额外的用户信息,如电子邮件、密码以及名字和姓氏。

CREATE TABLE users(
    id INT NOT NULL AUTO_INCREMENT,
    email VARCHAR(255),
    PRIMARY KEY (id)
);

权限(Permissons)

一旦我们有了用户,实现 RBAC 的第一步就是定义一组权限(或策略),并将每个权限与应用程序中的特权操作相关联。例如,您可以定义一个用户:创建权限,该权限与在应用程序中创建新用户的能力相关联。只有具有 user:create 权限的用户才能创建新用户。

要管理权限,我们实际上只需要每个权限都像用户一样具有唯一的 id。这足以将权限与角色相关联。为了使使用权限更人性化,我们将此 id 设置为唯一的字符串标识符(即类似 user:create 的标识符),而不是整数。这样,只需查看每个权限的 id 就可以很容易地理解它所代表的内容。

CREATE TABLE permissions(
    id VARCHAR(255) NOT NULL,
    PRIMARY KEY (id)
);

角色(Roles)

一旦我们定义了权限,就可以将它们以角色的形式组合在一起了。对于访问我们的应用程序的不同类型的用户来说,角色就像人物角色。这些人物角色将规定应该为每个角色将哪些权限分组在一起。例如,如果您的应用程序有一个免费层,其中包含所有用户都可以使用的基本功能,而高级层则包含仅付费用户可以使用的更强大的功能,那么您可以定义两个不同的角色:一个名为free_tier_user 的角色授予对所有基本功能的访问权限,另一个称为 premium_user 的作用授予对基本功能和高级功能的访问权。

角色的数据模型将与权限的模型完全相同。

CREATE TABLE roles(
    id VARCHAR(255) NOT NULL,
    PRIMARY KEY (id)
);

角色权限(Role Permissons)

由于每个角色都有权限,因此我们需要一种将权限与角色关联起来的方法。我们将此关系称为角色权限。为了表示角色权限,我们需要跟踪角色的 id 和我们关联在一起的权限的 id。请注意,权限可以属于多个角色。

CREATE TABLE role_permissions(
    role_id VARCHAR(255) NOT NULL,
    permission_id VARCHAR(255) NOT NULL,
    PRIMARY KEY (role_id, permission_id)
);

用户角色(User Roles)

由于用户将具有角色,因此我们还需要一种将用户与角色相关联的方法。我们将此关系称为用户角色。为了表示用户角色,我们需要跟踪角色的 id 和我们关联在一起的用户的 id。请注意,用户可以具有多个角色。

CREATE TABLE user_roles(
    role_id VARCHAR(255) NOT NULL,
    user_id INT NOT NULL,
    PRIMARY KEY (role_id, user_id)
);

授权(Authorization)

现在我们有了一个数据模型来存储和关联用户、角色和权限,我们可以使用权限来保护对系统中资源和操作的访问。我们需要(1)一种检查数据模型以确定用户是否有权限的方法,以及(2)一种在应用程序代码中的任何位置执行这些检查的简单方法。验证用户访问权限的过程称为授权

查询权限

我们可以通过查询我们的数据来了解试图获得访问权限的用户和获得访问权限所需的权限之间的关系,从而确定用户是否具有特定权限。

# Given a user id 15 and a permission id users:create,
# we can determine if the user has the required permission by:
# (1) Getting the user's role(s)
# (2) Checking if any of the user's roles grant them the required permission
SELECT *
FROM permissions
INNER JOIN role_permissions
    ON permissions.id = role_permissions.permission_id
WHERE
    permissions.id = "users:create" AND
    role_permissions.role_id IN (
        SELECT role_id
        FROM roles
        WHERE user_id = 15
    );

只有当 id15 的用户通过其角色之一拥有 users:create 权限时,上面的查询才会返回结果。否则,它将返回一个空结果,这意味着用户没有通过其任何角色获得所需的权限。

代码中的访问检查

为了便于在应用程序中的任何位置检查权限,您可以将上面的查询抽象为一个助手类或方法,该类或方法可以在代码中的任何地方调用。在JavaScript中,这可能看起来像:

class Authorization {
    // Returns true if the user has the
    // permission with the given permissionId
    static function hasPermission(userId, permissionId) {
        // NOTE: Assume getPermissionsForUser runs the SQL query from above
        const permissions = getPermissionsForUser(userId);

        return permissions.length > 0;
    }
}

然后,您可以调用此助手方法来保护应用程序中的操作:

function createUser(newUser) {
  const currentUserId = UserSession.getCurrentUserId();

  if (!Authorization.hasPermission(currentUserId, "users:create")) {
    throw new Error("Unauthorized attempt to create a new user!");
  }

  //
  // logic to create a new user
  //
}

最佳实践

实施良好的访问控制是为用户提供数据隐私和防止潜在数据丢失或被盗的最有效方法之一。在实现像RBAC这样的访问控制模型时,重要的是要记住以下几点:

  • 根据资源和操作定义权限(即users:create)。 这导致了定义良好的权限,即使您的角色和应用程序逻辑需要更改,这些权限也永远不需要更改。
  • 不要基于角色执行访问检查。 这可能是一种非常严格的方法,在不更新代码的情况下很难更改访问模型。相反,最好检查对权限的访问,因为这些权限直接映射到应用程序中的资源和操作。
  • 拥有集中的访问控制服务。 由于访问控制独立于应用程序的业务逻辑,因此最好将授权逻辑分离到自己的服务中。我们在上面用JavaScript实现的Authorization类中做到了这一点。

访问控制不是大多数应用程序的核心关注点,但关键是要做好。错误率非常低,即使是授权逻辑中的一个小问题也可能将特权数据和操作暴露给不应该访问它们的用户。

原文: https://blog.warrant.dev/implementing-role-based-access-control/

未分类    RBAC  

hefengbao

暂无个人简介

有0条评论

发表评论

您的电子邮箱地址不会被公开。 必填项已用 * 标注

来源:

https://www.8ug.icu/articles/implementing-role-based-access-control-in-a-web-application-LjGbEZ1Awx