Microsoft 标识平台采用以范围为中心的模型来访问资源。 此处,资源是指可以是访问令牌(如 MS 图形 API 或你自己的 Web API)的接收方的任何应用程序,范围(即“权限”)是指访问令牌授予权限的资源的任何方面。
访问令牌请求在MSAL.js中是按每个资源和每个范围分别进行的。 这意味着,为资源 A 请求的、作用域为 scp1 的 访问令牌:
- 不能用于以范围
scp2访问资源 A,并且, - 不能用于访问任何范围的资源 B 。
访问令牌的预期接收者由aud声明表示;如果声明的值aud与资源应用 ID URI 不匹配,则应将令牌视为无效。 同样, 访问令牌 授予的权限由 scp 声明表示。 有关详细信息 ,请参阅访问令牌声明 。
默认范围
默认情况下,MSAL.js 会向每个请求添加openidprofile和offline_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 图形 API 的 User.Read、User.Write 和 Calendar.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.js 的 login(即 loginPopup、loginRedirect)和 acquireToken(即 acquireTokenPopup、acquireTokenRedirect、acquireTokenSilent)方法。 请注意以下几点:
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.Read 和 api://<myCustomApiClientId>/My.Scope 这两个范围,但根据 每个资源每个范围 原则,他们只会收到用于 MS 图形 API 的 访问令牌。 但是,由于他们已经同意api://<myCustomApiClientId>/My.Scope,因此他们可以在以后以无提示方式获取该资源/范围的访问令牌。
同意有效期
在 Microsoft Entra ID 中,同意的生命周期超出了应用程序的生命周期。 这意味着,当你为某个资源请求访问令牌时,系统将返回你之前已为该资源授权同意的所有权限范围,而无论当时请求的是哪个权限范围。 换句话说,如果你今天同意 User.Read 和 Mail.Read,明天运行应用程序的新实例仅请求 User.Read 的访问令牌,你仍将收到同时为两者User.Read 和 Mail.Read 颁发的令牌。 有关详细信息,请参阅 权限和许可。