从身份验证上下文收到的令牌不起作用

Token received from authentication context not working

我正在设置多租户应用程序,但在创建 GraphServiceClient 时遇到问题。

我必须遵循 AuthorizationCodeReceived:

AuthorizationCodeReceived = async context =>
                    {
                        var tenantId =
                            context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;

                        var authenticationContext = new AuthenticationContext("https://login.microsoftonline.com/"+ tenantId);
                        await authenticationContext.AcquireTokenByAuthorizationCodeAsync(
                            context.Code,
                            new Uri("http://localhost:21925"),
                            new ClientCredential(ClientId, ClientSecret),
                            "https://graph.microsoft.com");
                    }

这非常适合对用户进行身份验证。我正在使用 fiddler,我看到 login.microsoftonline.com/{tenantid}/oauth2/token

给出了一个新的承载令牌

在创建新的图形服务客户端时,我使用了以下工厂方法:

public IGraphServiceClient CreateGraphServiceClient()
    {
        var client = new GraphServiceClient(
            new DelegateAuthenticationProvider(
                async requestMessage =>
                {
                    string token;
                    var currentUserId = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
                    var currentUserHomeTenantId = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
                    var authenticationContext = new AuthenticationContext("https://login.microsoftonline.com/" + currentUserHomeTenantId + "/");
                    var clientCredential = new ClientCredential(_configuration.ClientId, _configuration.ClientSecret);

                    try
                    {
                        var authenticationResult = await authenticationContext.AcquireTokenSilentAsync(
                            GraphResourceId,
                            clientCredential,
                            new UserIdentifier(currentUserId, UserIdentifierType.UniqueId));

                        token = authenticationResult.AccessToken;
                    }
                    catch (AdalSilentTokenAcquisitionException e)
                    {
                        var result = await authenticationContext.AcquireTokenAsync(GraphResourceId, clientCredential);
                            token = result.AccessToken;
                    }

                    requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", token);
                }));

        return client;
    }

此方法始终抛出 AdalSilentAcquisitionException 并且 AcquireTokenAsync 检索新令牌。

使用此令牌,我无法在图表上请求 'Me'。 我收到以下异常:消息=资源 'some guid' 不存在或其查询的 reference-property objects 之一不存在。

但是,如果我正在调试并且我在将令牌传递给 header 之前更改了令牌,其值为我之前在登录后立即获得的值(从 login.microsoftonline.com/ 收到{tenantid}/oauth2/token ) 然后 API 呼叫工作。

有谁知道我做错了什么?他能让获取令牌默默地工作吗?

更新: 我已经更新了代码示例。我已经删除了自定义缓存,现在一切似乎都正常了。

如何根据 http 会话创建自定义缓存,确保 AcquireTokenSilently 正常工作。

不工作的令牌缓存预览:

public class WebTokenCache : TokenCache
{
    private readonly HttpContext _httpContext;
    private readonly string _cacheKey;
    public WebTokenCache()
    {
        _httpContext = HttpContext.Current;
        var claimsPrincipal = (ClaimsPrincipal) HttpContext.Current.User;
        _cacheKey = BuildCacheKey(claimsPrincipal);

        AfterAccess = AfterAccessNotification;

        LoadFromCache();
    }

    private string BuildCacheKey(ClaimsPrincipal claimsPrincipal)
    {
        var clientId = claimsPrincipal.FindFirst("aud").Value;
        return $"{claimsPrincipal.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value}_TokenCache";
    }

    private void LoadFromCache()
    {
        var token = _httpContext.Cache[_cacheKey];
        if (token == null) return;

        Deserialize((byte[]) token);
    }

    private void AfterAccessNotification(TokenCacheNotificationArgs args)
    {
        if (!HasStateChanged) return;

        if (Count > 0)
        {
            _httpContext.Cache[_cacheKey] = Serialize();
        }
        else
        {
            _httpContext.Cache.Remove(_cacheKey);
        }

        HasStateChanged = false;
    }
}

我正在尝试使用上面的代码,它对我来说效果很好。

请确保 GraphResourceIdhttps://graph.microsoft.com(在您的启动 class 中首次请求此资源)因为方法 AcquireTokenSilentAsync 将尝试检索令牌基于资源的缓存。