通过


在 Node.js Web 应用程序中使用基于角色的访问控制

适用于绿色圆圈,带有白色复选标记符号,指示以下内容适用于外部租户。 外部租户(了解详细信息

基于角色的访问控制 (RBAC) 是一种在应用程序中强制进行授权的机制。 Microsoft Entra 外部 ID 允许为应用程序定义应用程序角色,并将这些角色分配给用户和组。 分配给用户或组的角色定义其对应用程序中资源和操作的访问级别。 当外部 ID 为经过身份验证的用户颁发安全令牌时,它包括你在安全令牌的角色声明中为用户或组分配的角色的名称。

还可配置外部租户,以返回用户的组成员身份。 然后,开发人员可使用安全组在应用程序中实现 RBAC,其中特定组中用户的成员身份会被解释为他们的角色成员身份。

将用户和组分配到角色后,角色声明将在安全令牌中发出。 但是,若要在安全令牌中发出 成员身份声明,需要在外部租户中执行其他配置。

本文介绍如何在 Node.js Web 应用的安全令牌中以声明的形式接收用户角色或组成员身份(或两者)。

先决条件

在 Node.js Web 应用中接收组和角色声明

配置外部租户后,可以在客户端应用中检索 角色 声明。 角色声明都在 ID 令牌和访问令牌中,但要在客户端实现授权,你的客户端应用只需在 ID 令牌中检查这些声明。 API 应用还可以在收到访问令牌时检索这些声明。

检查角色声明值,如以下代码片段示例所示

const msal = require('@azure/msal-node');
const { msalConfig, TENANT_SUBDOMAIN, REDIRECT_URI, POST_LOGOUT_REDIRECT_URI } = require('../authConfig');

...
class AuthProvider {
...
    async handleRedirect(req, res, next) {
        const authCodeRequest = {
            ...req.session.authCodeRequest,
            code: req.body.code, // authZ code
            codeVerifier: req.session.pkceCodes.verifier, // PKCE Code Verifier
        };
    
        try {
            const msalInstance = this.getMsalInstance(this.config.msalConfig);
            const tokenResponse = await msalInstance.acquireTokenByCode(authCodeRequest, req.body);
            let roles = tokenResponse.idTokenClaims.roles;
        
            //Check roles
            if (roles && roles.includes("Orders.Manager")) {
                //This user can view the ID token claims page.
                res.redirect('/id');
            }
            
            //User can only view the index page.
            res.redirect('/');
        } catch (error) {
            next(error);
        }
    }
...
}

如果将用户分配到多个角色,则 roles 字符串会包含用逗号分隔的所有角色,例如 Orders.Manager,Store.Manager,...。 请确保你生成应用程序是为了处理以下情况:

  • 令牌中缺少 roles 声明
  • 用户尚未分配到任何角色
  • 在将用户分配到多个角色时,roles 声明中有多个值。

也可以检查群组声明值,如以下代码片段示例所示:

const tokenResponse = await msalInstance.acquireTokenByCode(authCodeRequest, req.body);
let groups = tokenResponse.idTokenClaims.groups;

组声明值是组的 objectId。 如果用户是多个组的成员,则 groups 字符串会包含用逗号分隔的所有组,例如 7f0621bc-b758-44fa-a2c6-...,6b35e65d-f3c8-4c6e-9538-...

注释

如果向用户分配 Microsoft Entra 内置角色(通常也称为目录角色),这些角色会显示在安全令牌的组声明中。

处理组超额

为了确保安全令牌的大小不超过 HTTP 标头大小限制,外部 ID 会限制它在 声明中包含的对象 ID 数。 超额限制为 150(SAML 令牌)和 200(JWT 令牌)。 如果用户属于多个组,并且你请求了所有组,则可能会超出此限制。

在源代码中检测组超额

如果无法避免群组超量,则需要在代码中进行处理。 超出超额限制时,令牌不会包含组声明。 令牌会转而包含具有数组的组成员的 _claim_names 声明。 因此,你需要检查是否存在 _claim_names 声明,以确定是否出现了超额。 以下代码片段演示如何检测组超额:

const tokenResponse = await msalInstance.acquireTokenByCode(authCodeRequest, req.body);

if(tokenResponse.idTokenClaims.hasOwnProperty('_claim_names') && tokenResponse.idTokenClaims['_claim_names'].hasOwnProperty('groups')) {
    //overage has occurred
}

遵循在令牌中配置组声明和应用角色一文中的说明,了解发生组超额时如何请求完整的组列表。

如何在 Node.js Web 应用中使用组和角色值

在客户端应用中,可以验证登录用户是否具有访问受保护路由或调用 API 终结点所需的角色。 要做到这一点,您需要检查 ID 令牌中的 roles 声明。 若要在应用中实现此防护,可以使用自定义中间件生成防护。

在服务应用(API 应用)中,还可以保护 API 终结点。 验证客户端应用发送的访问令牌后,可以在访问令牌的有效负载声明中检查角色或组声明

我是使用应用角色还是组?

在本文中,你已了解可以使用应用角色来在应用程序中实现 RBAC。 首选方法是使用应用角色,因为它在应用程序级别管理访问/权限时提供更精细的控制。 有关如何选择方法的详细信息,请参阅选择方法

后续步骤