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

时间:2017-10-24 00:07:16

标签: azure-ad-b2c

我使用Visual Studio最新的 New Project 向导创建了一个ASP Core 2.0网页(Razor Pages),它使用个人帐户作为我的身份验证选项。我创建了一个Azure AD B2C租户并验证它是否正常工作。

当我运行向导创建的Web应用程序并单击右上角的登录时,它会重定向到我的Azure AD B2C站点,我可以正常登录。

登录后,回调网址将转到我的用户机密中配置的端点:

 ...
 "CallbackPath": "/signin-oidc",
 ...

这一切似乎都能正常运作。我了解Azure AD B2C门户将令牌发送回上述/signin-oidc回调路径并存储它。

如何检索该令牌的值?

我一直在关注所有Azure AD B2C指南,但并非所有指南都已更新到ASP Core 2.0,并且它们似乎都没有使用15.4 VS向导生成的代码:

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(sharedOptions =>
    {
        sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
    })
    .AddAzureAdB2C(options => Configuration.Bind("AzureAdB2C", options))
    .AddCookie();

    services.AddMvc();
}

注意:.AddAzureAdB2C(...)

没有一个B2C样本正在使用它,所以我很难遵循。

我的最终目标是获取令牌并将其用于我使用Autorest从Swagger生成的强类型API类中,这些API类需要令牌。

2 个答案:

答案 0 :(得分:2)

Azure AD B2C .Net Core示例中概述了执行此操作的最佳方法,特别是branch for Core 2.0

在普通模型/流程中,您的应用程序将获得id_token和授权代码,但不会获得令牌。您的中间层需要交换授权代码。您可以将此令牌发送到您的网络API。

执行此操作的方法包括以下内容:

  1. 确保您的中间层请求主要政策的id_token +代码(您不希望为编辑个人资料或密码重置政策执行此操作)。来自示例OpenIdConnectOptionsSetup.cs#L77
  2. 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
    2. 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。来自示例HomeController.cs#L45-L57
      2. 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);
        

答案 1 :(得分:1)

ASP.NET核心团队在此过程中创建了2个优秀文档。