我们使用 axios 请求拦截器从 MSAL.js 获取访问令牌,并将其作为不记名令牌添加到我们后端的所有 API 请求中:
async acquireToken() {
const accounts = msalInstance.getAllAccounts();
if (accounts.length === 0) return null;
const request = {
scopes: process.env.scopes || [],
account: accounts[0],
};
try {
return await msalInstance.acquireTokenSilent(request);
} catch (error) {
if (error instanceof InteractionRequiredAuthError) {
return await msalInstance.acquireTokenPopup(request);
}
return null;
}
}
async getAccessToken() {
const token = await acquireToken();
return token?.accessToken || '';
}
axiosInstance.interceptors.request.use(
async (config) => {
const configured = config;
const token = await getAccessToken();
configured.headers.Authorization = `Bearer ${token}`;
return configured;
},
(error: any) => Promise.reject(error)
);
当用户在应用程序内打开某个路由时,会同时发送多个请求,如下所示:
useEffect(() => {
Promise.all([getMovies(), getActors()]).then(([_movies, _actors]) => {
// ...
});
}, []);
我们真的不想按顺序进行调用,因为其中一些调用可能很慢,并行运行它们可以提高效率。
问题是,每当所有令牌过期并且需要交互式登录时,所有并行请求都属于 aquireTokenPopup 的范围,并且只有其中一个正在工作,另一个则失败并出现 interaction_in_progress 错误。
MSAL 文档说 aquireTokenSilent
returns currently processing promise if parallel requests are made
- 为什么 aquireTokenPopup 的情况并非如此?
https://learn.microsoft.com/en-us/javascript/api/@azure/msal-browser/publicclientapplication?view=msal-js-latest#method-details
处理这种情况的最佳方法是什么?是否有一些库可以封装此 MSAL 调用,并且如果同时进行多个调用(如果 MSAL 本身没有执行此操作),则仅启动一个调用?或者我是否遗漏了某些内容,并且从 axios 请求拦截器中调用 MSAL 根本不是一个好主意?
看起来这个简单的添加解决了问题,但我仍然想知道为什么 MSAL 不这样做以及这是否是一个合适的解决方案。
private currentTokenPromise: Promise<string> | null = null;
getAccessToken() {
if (this.currentTokenPromise) {
return this.currentTokenPromise;
}
const tokenPromise = this.acquireToken().then((t) => {
this.currentTokenPromise = null;
return t?.accessToken || '';
});
this.currentTokenPromise = tokenPromise;
return tokenPromise;
}