资源和范围

Microsoft 标识平台采用以范围为中心的模型来访问资源。 此处,资源是指可以是访问令牌(如 MS 图形 API 或你自己的 Web API)的接收方的任何应用程序,范围(“权限”)是指访问令牌授予权限的资源的任何方面。

访问令牌请求在MSAL.js中是按每个资源和每个范围分别进行的。 这意味着,为资源 A 请求的、作用域为 scp1访问令牌

  • 不能用于以范围 scp2 访问资源 A,并且,
  • 不能用于访问任何范围的资源 B

访问令牌的预期接收者由aud声明表示;如果声明的值aud与资源应用 ID URI 不匹配,则应将令牌视为无效。 同样, 访问令牌 授予的权限由 scp 声明表示。 有关详细信息 ,请参阅访问令牌声明

默认范围

默认情况下,MSAL.js 会向每个请求添加openidprofileoffline_access作用域。 需要这些范围才能接收刷新令牌和用于填充帐户对象用户信息的 id 令牌声明。

使用多个资源

若要访问多个资源,请为每个资源启动单独的令牌请求:

// "User.Read" stands as shorthand for "graph.microsoft.com/User.Read"
const graphToken = await msalInstance.acquireTokenSilent({
     scopes: [ "User.Read" ]
});
const customApiToken = await msalInstance.acquireTokenSilent({
     scopes: [ "api://<myCustomApiClientId>/My.Scope" ]
});

请注意,您可以为同一资源请求多个作用域(例如,MS 图形 APIUser.ReadUser.WriteCalendar.Read)。

const graphToken = await msalInstance.acquireTokenSilent({
     scopes: [ "User.Read", "User.Write", "Calendar.Read" ] // all MS Graph API scopes
});

如果你在令牌请求中错误地传入了多个资源,则返回给你的令牌只会针对第一个资源签发。

// you will only receive a token for MS GRAPH API's "User.Read" scope here
const myToken = await msalInstance.acquireTokenSilent({
     scopes: [ "User.Read", "api://<myCustomApiClientId>/My.Scope" ]
});

Microsoft Entra ID中,直接在应用程序注册上设置的范围(权限)称为静态作用域。 仅在代码中定义的其他范围称为 动态作用域。 这会影响 MSAL.jslogin(即 loginPopuploginRedirect)和 acquireToken(即 acquireTokenPopupacquireTokenRedirectacquireTokenSilent)方法。 请注意以下几点:

 const loginRequest = {
      scopes: [ "openid", "profile", "User.Read" ]
 };
 const tokenRequest = {
      scopes: [ "Mail.Read" ]
 };
 // will return an ID Token and an Access Token with scopes: "openid", "profile" and "User.Read"
 msalInstance.loginPopup(loginRequest);
 // will fail and fallback to an interactive method prompting a consent screen
 // after consent, the received token will be issued for "openid", "profile" ,"User.Read" and "Mail.Read" combined
 msalInstance.acquireTokenSilent(tokenRequest);

在上面的代码片段中,在用户进行身份验证并接收 ID 令牌和具有作用域User.Read后,系统会提示用户同意。 稍后,如果他们请求访问令牌User.Read,则不会再次请求同意(换句话说,他们可以静默获取令牌)。

另一方面,用户在身份验证阶段未对 Mail.Read 表示同意,因此,在为 Mail.Read 范围请求 访问令牌 时,系统会要求其提供同意。 收到的令牌将包含此前已同意的该特定资源的所有权限范围,因此称为 增量同意

请考虑略有不同的情况:

 const loginRequest = {
      scopes: [ "openid", "profile", "User.Read" ],
      extraScopesToConsent: [ "api://<myCustomApiClientId>/My.Scope"]
 };
 const tokenRequest = {
      scopes: [ "Mail.Read" ]
 };
 const anotherTokenRequest = {
      scopes: [ "api://<myCustomApiClientId>/My.Scope" ]
 }
 // will return an ID Token and an Access Token with scopes: "openid", "profile" and "User.Read"
 msalInstance.loginPopup(loginRequest);
 // will fail with InteractionRequiredError due to lack of consent for "Mail.Read" scope. You should fallback to an interactive method in this case.
 msalInstance.acquireTokenSilent(tokenRequest);
 // will succeed and return an Access Token with scope "api://<myCustomApiClientId>/My.Scope"
 msalInstance.acquireTokenSilent(anotherTokenRequest);

在上面的代码片段中,尽管用户同意了 User.Readapi://<myCustomApiClientId>/My.Scope 这两个范围,但根据 每个资源每个范围 原则,他们只会收到用于 MS 图形 API访问令牌。 但是,由于他们已经同意api://<myCustomApiClientId>/My.Scope,因此他们可以在以后以无提示方式获取该资源/范围的访问令牌

在 Microsoft Entra ID 中,同意的生命周期超出了应用程序的生命周期。 这意味着,当你为某个资源请求访问令牌时,系统将返回你之前已为该资源授权同意的所有权限范围,而无论当时请求的是哪个权限范围。 换句话说,如果你今天同意 User.ReadMail.Read,明天运行应用程序的新实例仅请求 User.Read访问令牌,你仍将收到同时为两者User.ReadMail.Read 颁发的令牌。 有关详细信息,请参阅 权限和许可