MSAL.js 中的缓存

当 MSAL 获取令牌时,它会缓存令牌以供将来使用。 MSAL 为你管理令牌生存期和刷新。 acquireTokenSilent() API 从给定帐户的缓存中检索访问令牌,并根据需要续订它们。

缓存存储

可以通过用于实例化 MSAL 的配置对象配置缓存存储位置:

import { PublicClientApplication, BrowserCacheLocation } from "@azure/msal-browser";

const pca = new PublicClientApplication({
    auth: {
        clientId: "Enter_the_Application_Id_Here", // e.g. "00001111-aaaa-2222-bbbb-3333cccc4444" (guid)
        authority: "https://login.microsoftonline.com/Enter_the_Tenant_Info_Here", // e.g. "common" or your tenantId (guid),
        redirectUri: "/"
    },
    cache: {
       cacheLocation: BrowserCacheLocation.SessionStorage // "sessionStorage"
    }
});

默认情况下,MSAL 使用所有现代浏览器均支持的 Web Storage API,将它从 IdP 获取的各种身份验证项目存储在浏览器存储中。 因此,MSAL 提供两种持久性存储方法: sessionStorage (默认值)和 localStorage。 此外,MSAL 还提供了一个 memoryStorage 选项,允许你选择不将缓存存储在浏览器存储中。

缓存位置 清除时间 在窗口/标签页之间共享 支持的重定向流
sessionStorage 窗口/选项卡关闭 No 是的
localStorage 浏览器关闭时(除非用户已选择“保持登录状态”) 是的 是的
memoryStorage 页面刷新/导航 No No

注释

虽然由于窗口/选项卡关闭或页面刷新/导航,身份验证状态在会话和内存存储中可能会丢失,但只要会话 Cookie 未过期,用户仍具有与 IdP 的活动会话,并且可能能够在没有任何提示的情况下重新进行身份验证。

不同存储位置之间的选择反映了更好的用户体验与提高安全性之间的权衡。 如上表所示,本地存储可获得最佳用户体验,而内存存储提供最佳安全性,因为浏览器存储中没有存储敏感信息。 有关详细信息,请参阅下面的安全和缓存项目部分。

LocalStorage 注意事项

从 v4 开始,如果使用 localStorage 缓存位置,身份验证项目将加密,除非用户在登录期间选择“使我保持登录状态”。 所使用的加密算法是 AES-GCM,并使用 HKDF 派生密钥。 基键存储在标题为 msal.cache.encryption的会话 Cookie 中。

当浏览器实例(而非标签页)关闭时,此 Cookie 会被自动删除,从而无法在会话结束后解密任何身份验证工件。 下次初始化 MSAL 时,将删除这些过期的身份验证项目,用户可能需要重新进行身份验证。 该 localStorage 位置仍为所有用户提供跨选项卡缓存持久性,但仅针对选择“使我保持登录状态”(KMSI)的用户跨浏览器会话保留。

Important

此加密的目的是减少身份验证项目的持久性, 而不是 提供额外的安全性。 如果不良参与者获得对浏览器存储的访问权限,则他们也可以访问密钥,或者能够代表你请求令牌,而无需缓存。 确保应用程序不会容易受到 XSS 攻击,这是你的责任。 有关详细信息,请参阅 安全 部分。

注释

MSAL.js v4 中弃用临时身份验证项目的 Cookie 存储。 此部分保留给仍在使用 MSAL.js v3 或更早版本的应用程序。

可以将 MSAL 浏览器配置为使用 Cookie 来存储临时身份验证项目。 此选项可让您支持那些在基于重定向的登录流程中可能会清除本地存储/会话存储的浏览器(例如 Internet Explorer 和隐私模式下的 Firefox)。 请注意,选择此选项后,令牌本身仍存储在浏览器或内存存储中。 有关详细信息,请参阅 配置

安全性

只要应用程序没有跨站点脚本(XSS)和相关漏洞,我们就可以考虑会话/本地存储安全。 请参阅 OWASP XSS 防护备忘单 来保护应用程序免受 XSS 攻击。 如果仍担心,建议改用此选项 memoryStorage

缓存项目

为了在保持良好用户体验的同时高效获取令牌,MSAL 会缓存其 API 调用产生的各种数据。 下面是 MSAL 缓存中实体的摘要:

  • 持久性工件(在请求结束后仍然存在——另请参见:令牌生存期
    • 访问令牌
    • ID 令牌
    • 刷新令牌
    • 账户
  • 临时项目(限于请求生存期)
    • 请求元数据(例如状态、nonce、authority)
    • 错误
    • 交互状态
  • 遥测
    • 上一个失败的请求
    • 性能数据

注释

临时缓存条目始终存储在会话存储或内存中。 如果会话存储不可用,MSAL 会回退到内存存储。

注释

授权代码仅存储在内存中,并在兑换令牌后被丢弃。

temporaryCacheLocation 覆盖

注释

在 MSAL.js v4 中,temporaryCacheLocation 配置选项已弃用。 此部分保留给仍在使用 MSAL.js v3 或更早版本的应用程序。

Warning

重写 temporaryCacheLocation 时应谨慎,尤其是在选择 localStorage 时。 不支持多个选项卡/窗口中的交互,你可能会意外收到 interaction_in_progress 错误。 这是一种权宜之计,并非受完全支持的功能。

在默认配置下使用 MSAL.js 时,如果用户在成功完成身份验证后被重定向到新的窗口或选项卡中,则带 PKCE 的 OAuth 2.0 授权码流程将被中断。 在这种情况下,存储身份验证状态(代码验证者和质询)的原始窗口或选项卡将丢失,身份验证流将失败。

若要处理这种情况,可以通过重写 temporaryCacheLocation 配置属性,将 MSAL 配置为使用 localStorage 作为缓存位置。 这样就可以将代码验证器和质询码存储在浏览器的 localStorage 中,并且该存储可在多个标签页和窗口之间持续保留。

MSAL.js 升级和回滚期间的缓存持久性

有时 MSAL.js 需要更改缓存项目的形状,以支持新的要求、功能或 bug 修复。 这些更改通常以向后兼容的方式进行,以确保应用程序升级到新版本或回滚到旧版本时,仍可使用用户浏览器中存在的缓存。 但是,这并非总是可能的,最终可能会同时存在缓存的多个副本,其中一个副本由当前版本的 MSAL.js 运行,另一个由升级前使用的版本写入。 这样做是为了让应用程序在需要时能够平稳回滚。 在绝大多数升级中,MSAL.js 将任何现有缓存迁移到新格式,实现无缝升级体验。 在极少数情况下,例如从 v3 升级到 v4,由于安全或隐私要求,这可能无法实现,而且这始终会导致主版本号升级。

发生中断性缓存更改时,旧缓存默认保留 5 天,以便在需要时进行回滚。 旧缓存的保留时长可以通过 PublicClientApplication 上的 cacheRetentionDays 缓存配置来设置。 如果缓存在该时间内未主动使用,则会在下一次初始化 MSAL.js 时将其清除。 此外,如果预计不需要回滚,则可以将此值 0 设置为指示在升级到新版本 MSAL.js后,应立即删除旧缓存。 相反,如果你有一个较长的升级推出窗口,则可以选择将此值设置为更长的值。

注释

访问和刷新令牌一旦过期就会被删除,即使配置的 cacheRetentionDays 尚未达到。 如果浏览器存储达到其存储配额,也可以随时删除有效的访问令牌。 达到存储配额后,首先先从以前版本的 MSAL.js 写入的条目开始删除访问令牌,然后转到当前版本的 MSAL.js编写的条目。

const config = {
    auth: {
        clientId: "<your-client-id>"
    },
    cache: {
        cacheLocation: "localStorage",
        cacheRetentionDays: 0 // Set this to the number of days you want old cache to be preserved in the event a rollback is needed (Default 5 days)
    }
}

const pca = new PublicClientApplication(config);
await pca.initialize();

注解

  • 不建议使用依赖于直接使用缓存中的实体的业务逻辑的应用。 需要获取令牌或检索帐户时,请改用相应的 MSAL API。
  • 用于加密所有权证明(PoP)令牌的密钥使用 IndexedDB API 和内存存储的组合进行存储。 有关更多信息,请参阅access-token-proof-of-possession

详细信息