且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何获取ASP Core 2.0中从Azure AD B2C返回的令牌?

更新时间:2023-02-14 22:57:26

Azure AD B2C .Net Core示例概述了***方法,特别是

The best way to do this is outlined in the Azure AD B2C .Net Core sample, specifically the branch for Core 2.0.

在正常模型/流中,您的应用程序将获得id_token和授权码,但不会获得令牌.您的中间层需要将授权代码交换为令牌.该令牌就是您要发送到Web API的令牌.

In the normal model/flow, your application will get an id_token and an authorization code but not a token. The authorization code needs to be exchanged for a token by your middle tier. This token is what you'd then be sending over to your web API.

执行此操作的方法涉及以下内容:

The way to do this involves the following:

  1. 确保您的中间层正在为您的主要策略请求id_token + code(您不想为您的编辑配置文件或密码重置策略执行此操作).从样本的 OpenIdConnectOptionsSetup.cs#L77 :

public Task OnRedirectToIdentityProvider(RedirectContext context)
{
    var defaultPolicy = AzureAdB2COptions.DefaultPolicy;
    if (context.Properties.Items.TryGetValue(AzureAdB2COptions.PolicyAuthenticationProperty, out var policy) &&
        !policy.Equals(defaultPolicy))
    {
        context.ProtocolMessage.Scope = OpenIdConnectScope.OpenIdProfile;
        context.ProtocolMessage.ResponseType = OpenIdConnectResponseType.IdToken;
        context.ProtocolMessage.IssuerAddress = context.ProtocolMessage.IssuerAddress.ToLower().Replace(defaultPolicy.ToLower(), policy.ToLower());
        context.Properties.Items.Remove(AzureAdB2COptions.PolicyAuthenticationProperty);
    }
    else if (!string.IsNullOrEmpty(AzureAdB2COptions.ApiUrl))
    {
        context.ProtocolMessage.Scope += $" offline_access {AzureAdB2COptions.ApiScopes}";
        // -----------------------------
        // THIS IS THE IMPORTANT PART:
        context.ProtocolMessage.ResponseType = OpenIdConnectResponseType.CodeIdToken;
        // -----------------------------
    }
    return Task.FromResult(0);
}

  1. 将代码交换为令牌.来自样本的 OpenIdConnectOptionsSetup.cs#L103-L124 :

public async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
{
    // Use MSAL to swap the code for an access token
    // Extract the code from the response notification
    var code = context.ProtocolMessage.Code;

    string signedInUserID = context.Principal.FindFirst(ClaimTypes.NameIdentifier).Value;
    TokenCache userTokenCache = new MSALSessionCache(signedInUserID, context.HttpContext).GetMsalCacheInstance();
    ConfidentialClientApplication cca = new ConfidentialClientApplication(AzureAdB2COptions.ClientId, AzureAdB2COptions.Authority, AzureAdB2COptions.RedirectUri, new ClientCredential(AzureAdB2COptions.ClientSecret), userTokenCache, null);
    try
    {
        AuthenticationResult result = await cca.AcquireTokenByAuthorizationCodeAsync(code, AzureAdB2COptions.ApiScopes.Split(' '));
        context.HandleCodeRedemption(result.AccessToken, result.IdToken);
    }
    catch (Exception ex)
    {
        //TODO: Handle
        throw;
    }
}

  1. 然后您可以在代码的其他地方使用此令牌来调用API.从样本的
    var scope = AzureAdB2COptions.ApiScopes.Split(' ');
    string signedInUserID = HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;
    TokenCache userTokenCache = new MSALSessionCache(signedInUserID, this.HttpContext).GetMsalCacheInstance();
    ConfidentialClientApplication cca = new ConfidentialClientApplication(AzureAdB2COptions.ClientId, AzureAdB2COptions.Authority, AzureAdB2COptions.RedirectUri, new ClientCredential(AzureAdB2COptions.ClientSecret), userTokenCache, null);
    
    
    AuthenticationResult result = await cca.AcquireTokenSilentAsync(scope, cca.Users.FirstOrDefault(), AzureAdB2COptions.Authority, false);
    
    
    HttpClient client = new HttpClient();
    HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, AzureAdB2COptions.ApiUrl);
    
    
    // Add token to the Authorization header and make the request
    request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
    HttpResponseMessage response = await client.SendAsync(request);