我有一个使用
@azure/msal-browser: ^3.22.0
的精简应用程序
实际上调用
acquireTokenSilent
应该从缓存中检索我的有效 accessToken,并且仅当它无效或过期时才获取新的。
但就我而言,方法调用总是获取新令牌并更新缓存。因此,对于每个 api 调用,都会创建一个新令牌。
这里有什么问题?
方法如下。每次 api 调用都会调用
getToken
,但不应始终创建新令牌:
export async function getToken(clientId, mail) {
let tokenRes;
let loginReq = getLoginRequest(clientId);
tokenRes = await acquireToken(loginReq, mail);
if (!tokenRes) {
return null;
}
return tokenRes.accessToken;
}
function acquireToken(req, mail) {
req.account = msalInstance.getAccount({ username: mail });
return msalInstance.acquireTokenSilent(req).catch((error) => {
if (error instanceof msal.InteractionRequiredAuthError) {
return msalInstance.acquireTokenRedirect(req);
}
});
}
if (!tokenResponse) {
return null;
}
return tokenResponse.accessToken;
}
function acquireToken(request, mailAddress) {
request.account = msalInstance.getAccount({ username: mailAddress });
return msalInstance.acquireTokenSilent(request).catch((error) => {
console.error(error);
if (error instanceof msal.InteractionRequiredAuthError) {
console.warn('Silent token acquisition fails. Use fallback acquiring token using redirect.');
return msalInstance.acquireTokenRedirect(request);
}
});
}
我在Microsoft微软官方文档中找到了解决方案:
它解释说“MSAL 根据范围、资源和权限等特定参数使用缓存来存储令牌,并在需要时从缓存中检索令牌。当这些令牌过期时,它还可以执行静默续订。MSAL通过 acquireTokenSilent 方法公开此功能。”
范围至关重要,因为它们决定缓存的令牌是否可以重用。
在我的
getLoginRequest
方法中,范围定义为:
scopes: [
"api://${id}/myApi.Read",
"api://${id}/myApi.Write",
"openid",
"profile",
"offline_access",
"email",
"User.Read"
]
这就是问题出现的地方。我正在请求范围
openid, profile, offline_access, email, and User.Read
。然而,这些范围似乎并未在检索到的令牌中设置。结果,每次我调用 acquireTokenSilent
时,它都会识别缓存中的令牌,但由于令牌缺少请求的范围,因此它会丢弃旧令牌并尝试获取新令牌。不幸的是,新令牌仍然没有包含必要的范围,导致循环重复。
当删除不存在的范围时,tokenCache 可以正常工作。