如何解决MSAL.js中acquireTokenSilent多范围请求的AADB2C90146错误?
解决MSAL.js静默获取多范围令牌时的AADB2C90146错误
嘿,这个问题我碰到过好几次了,核心原因很明确:AADB2C的acquireTokenSilent方法一次只能针对单个资源请求访问令牌。你传入的范围里既有两个不同资源的user_impersonation,又混了openid/profile这类ID令牌专属范围,直接违反了这个限制,所以才会报错。
为什么之前能正常工作?
大概率是你之前的所有范围都属于同一个资源,或者是用了隐式流这类对多范围限制更宽松的方式。现在得调整成符合B2C令牌获取规则的做法。
正确的处理步骤
1. 按资源拆分范围,单独获取令牌
把不同资源的范围拆分开,多次调用acquireTokenSilent,每个请求只对应一个资源:
// 获取第一个资源的访问令牌 const firstResourceToken = await this.clientApplication.acquireTokenSilent({ scopes: ["https://xxx.onmicrosoft.com/xxx/user_impersonation"], account: this.clientApplication.getActiveAccount() // 必须指定当前登录账户 }); // 获取第二个资源的访问令牌 const secondResourceToken = await this.clientApplication.acquireTokenSilent({ scopes: ["https://yyy.onmicrosoft.com/yyy/user_impersonation"], account: this.clientApplication.getActiveAccount() });
这样每个请求只针对单一资源,就不会触发那个讨厌的AADB2C90146错误了。
2. 单独处理ID令牌范围(openid/profile)
openid和profile是用来获取ID令牌的,不是访问令牌的资源范围。ID令牌会在用户首次登录时自动获取,MSAL也会自动帮你刷新它的生命周期——除非你有特殊需求,否则根本不需要把它们和访问令牌的范围混在一起请求。
如果确实需要显式刷新ID令牌,可以单独调用:
const idTokenRefreshResponse = await this.clientApplication.acquireTokenSilent({ scopes: ["openid", "profile"], account: this.clientApplication.getActiveAccount() });
不过一般情况下,MSAL会在需要的时候自动处理ID令牌的刷新,不用你手动干预。
3. 用Promise.all批量处理多资源请求
如果要获取多个资源的令牌,用Promise.all并行调用可以提高效率:
const activeAccount = this.clientApplication.getActiveAccount(); const resourceScopes = [ ["https://xxx.onmicrosoft.com/xxx/user_impersonation"], ["https://yyy.onmicrosoft.com/yyy/user_impersonation"] ]; // 并行获取所有资源的令牌 const allTokenResponses = await Promise.all( resourceScopes.map(scopes => this.clientApplication.acquireTokenSilent({ scopes, account: activeAccount }) ) ); // 之后可以从allTokenResponses中分别取出每个资源的accessToken使用
几个关键提醒
- 每个
acquireTokenSilent调用的scopes里,所有范围必须属于同一个资源(也就是开头的域名部分要完全一致)。 - 一定要传入
account参数,MSAL需要明确知道是给哪个用户获取令牌,避免混乱。 - 别忘了捕获静默获取失败的情况(比如令牌过期且没有可用的刷新令牌),这时候要触发交互式登录(比如
acquireTokenPopup或acquireTokenRedirect)来重新获取令牌。
内容的提问来源于stack exchange,提问作者Marc C
相关产品推荐
相关产品推荐

