You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在MSAL.NET中缓存移动端获取的JWT及访问/刷新令牌?

解决方案:将移动端令牌存入MSAL.NET用户令牌缓存

由于新版MSAL.NET的AcquireTokenOnBehalfOf不再将刷新令牌持久化到用户令牌缓存,你可以通过手动构造令牌缓存条目并添加到MSAL缓存的方式,实现从移动端传递的令牌持久化,具体步骤和代码如下:

核心思路

MSAL.NET的用户令牌缓存本质是可序列化的存储结构,你可以直接将移动端获取的合法令牌(刷新令牌、访问令牌、ID令牌)构造为符合MSAL格式的缓存条目,添加到缓存后触发持久化操作,后续即可正常调用Graph API时自动复用缓存中的令牌。

关键注意事项

  • 移动端传递的刷新令牌必须是针对后端Web应用的客户端ID生成的,刷新令牌与客户端ID绑定,跨客户端无法复用。
  • 需从ID令牌中解析出用户唯一标识(如oid或sub声明),确保缓存与用户身份正确关联。
  • 自定义缓存提供者(如你的MuTokenCacheProvider)需正确实现缓存的初始化与持久化逻辑。

代码实现示例

方法1:直接构造MsalTokenCacheItem添加到缓存

public async Task<ActionResult> CacheMobileTokens(
    string idToken, 
    string refreshToken, 
    string accessToken, 
    DateTimeOffset expiresOn, 
    string[] scopes, 
    string tenantId, 
    string userId)
{
    // 初始化ConfidentialClientApplication
    var app = ConfidentialClientApplicationBuilder.Create(clientId)
        .WithClientSecret(clientSecret)
        .WithRedirectUri(redirectUrl)
        .Build();

    // 关联自定义缓存提供者到当前用户
    var tokenCacheProvider = ((MuTokenCacheProvider)_cacheProvider);
    tokenCacheProvider.Initialize(app.UserTokenCache, userId);

    // 从ID令牌构造用户ClaimsPrincipal
    var jwtToken = new JwtSecurityToken(idToken);
    var claimsIdentity = new ClaimsIdentity(jwtToken.Claims, "JWT");
    var user = new ClaimsPrincipal(claimsIdentity);

    // 构造MSAL令牌缓存条目
    var tokenCacheEntry = new MsalTokenCacheItem(
        clientId: app.ClientId,
        homeAccountId: $"{userId}.{tenantId}", // 格式:用户ID.租户ID
        realm: tenantId,
        secret: accessToken,
        refreshToken: refreshToken,
        expiresOn: expiresOn.UtcDateTime,
        scopes: scopes,
        idToken: idToken,
        user: user);

    // 将条目添加到缓存
    app.UserTokenCache.AddTokenCacheItem(tokenCacheEntry);

    // 触发缓存持久化(根据自定义缓存提供者逻辑调整)
    await app.UserTokenCache.SaveAsync();

    return Ok();
}

方法2:通过MSAL V3格式JSON反序列化加载缓存

如果更倾向于序列化方式,可构造符合MSAL V3缓存规范的JSON,再反序列化到缓存:

public async Task<ActionResult> CacheMobileTokensViaJson(string cacheJson)
{
    var app = ConfidentialClientApplicationBuilder.Create(clientId)
        .WithClientSecret(clientSecret)
        .WithRedirectUri(redirectUrl)
        .Build();

    // 初始化自定义缓存提供者
    var tokenCacheProvider = ((MuTokenCacheProvider)_cacheProvider);
    tokenCacheProvider.Initialize(app.UserTokenCache, myUserId);

    // 将JSON反序列化到令牌缓存
    var cacheBytes = Encoding.UTF8.GetBytes(cacheJson);
    app.UserTokenCache.DeserializeMsalV3(cacheBytes);

    // 持久化缓存
    await app.UserTokenCache.SaveAsync();

    return Ok();
}

对应的JSON格式示例:

{
  "HomeAccountId": "用户ID.租户ID",
  "Environment": "https://login.microsoftonline.com",
  "Realm": "租户ID",
  "LocalAccountId": "用户ID",
  "Username": "user@example.com",
  "RefreshToken": "移动端获取的刷新令牌",
  "IdToken": "移动端获取的ID令牌",
  "AccessToken": "移动端获取的访问令牌",
  "ExpiresOn": "2024-12-31T23:59:59.000Z",
  "Scopes": ["email", "Calendars.ReadWrite"]
}

后续使用

完成令牌缓存后,后续调用Graph API时,直接使用AcquireTokenSilent即可自动复用缓存中的令牌:

var result = await app.AcquireTokenSilent(scopes, user)
    .ExecuteAsync();

内容的提问来源于stack exchange,提问作者Matt Roberts

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 19:45:54