Asp.net mvc 在与Azure AD B2C集成的网站中获取访问令牌

Asp.net mvc 在与Azure AD B2C集成的网站中获取访问令牌,asp.net-mvc,azure,asp.net-core,azure-ad-b2c,Asp.net Mvc,Azure,Asp.net Core,Azure Ad B2c,我有一个ASP.NET MVC Core 2.2应用程序,它与Azure AD B2C集成以验证用户。我可以正确登录,并且用户已通过身份验证 我还创建了一个ASP.NET核心Web API,它也与Azure B2C广告集成,目标是从ASP.NET MVC控制器操作方法调用该Web API 因此,我在MVC站点的控制器中添加了以下测试代码: if (HttpContext.User.Identity.IsAuthenticated) { string signedInUserID = Ht

我有一个ASP.NET MVC Core 2.2应用程序,它与Azure AD B2C集成以验证用户。我可以正确登录,并且用户已通过身份验证

我还创建了一个ASP.NET核心Web API,它也与Azure B2C广告集成,目标是从ASP.NET MVC控制器操作方法调用该Web API

因此,我在MVC站点的控制器中添加了以下测试代码:

if (HttpContext.User.Identity.IsAuthenticated)
{
    string signedInUserID = HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;
    TokenCache userTokenCache = new MSALSessionCache(signedInUserID, HttpContext).GetMsalCacheInstance();
    ConfidentialClientApplication cca = new ConfidentialClientApplication(mgpPortalApplicationId, authority, redirectUri, new ClientCredential(mgpPortalSecretKey), userTokenCache, null);                
    IEnumerable<IAccount> accounts = await cca.GetAccountsAsync();
    IAccount firstAccount = accounts.FirstOrDefault();
    AuthenticationResult result = await cca.AcquireTokenSilentAsync(null, firstAccount, authority, false);
    HttpClient client = new HttpClient();
    HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "https://localhost:44307/api/values");
    request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
    HttpResponseMessage response = await client.SendAsync(request);
}
if(HttpContext.User.Identity.IsAuthenticated)
{
string signedInUserID=HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;
TokenCache userTokenCache=新的MSALSessionCache(SignedUserId,HttpContext)。GetMsalCacheInstance();
机密客户端应用程序cca=新的机密客户端应用程序(mgpPortalApplicationId、权限、重定向URI、新客户端凭据(mgpPortalSecretKey)、userTokenCache、null);
IEnumerable accounts=wait cca.GetAccountsAsync();
IAccount firstAccount=accounts.FirstOrDefault();
AuthenticationResult=等待cca.AcquireTokenSilentAsync(null,firstAccount,authority,false);
HttpClient=新的HttpClient();
HttpRequestMessage请求=新建HttpRequestMessage(HttpMethod.Get)https://localhost:44307/api/values");
request.Headers.Authorization=新的AuthenticationHeaderValue(“承载者”,result.AccessToken);
HttpResponseMessage response=等待客户端.SendAsync(请求);
}
问题是
accounts.FirstOrDefault()
返回null。不确定原因:

  • signedInUserID包含登录用户的标识符
  • mgpPortalApplicationId是MVC站点的应用程序ID
  • 权限为“”
  • 重定向URI为“”
  • mgpPortalSecretKey包含我将MVC应用程序添加到B2C租户时生成的秘密
有人知道我做错了什么吗?谢谢你的提示


其他观察结果:如果我运行使用旧版Microsoft.Identity.Client的演示,那么对cca.Users.FirstOrDefault()的调用将正确返回用户。但是,当我将此演示项目升级到Microsoft.Identity.Client 2.7(这是.NET Core 2.2所需的)时,我必须传递一个IAccount,因此我需要调用
GetAccountsAsync()
,这将返回noaccount

首先,在调用AcquireTokenSilentAsync时,需要询问访问api所需的作用域

AuthenticationResult result = await cca.AcquireTokenSilentAsync(scope, cca.Users.FirstOrDefault(), AzureAdB2COptions.Authority, false);
您需要使用授权中间件的
AuthorizationCodeReceived
通知实现初始令牌获取并将令牌保存在MSAL令牌缓存中:

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;
    }
}
因此,当在控制器中获取令牌时,MSAL将查找缓存并返回与需求匹配的任何缓存令牌。如果此类访问令牌已过期或不存在合适的访问令牌,但存在关联的刷新令牌,MSAL将自动使用该刷新令牌获取新的访问令牌并以透明方式返回:

// Retrieve the token with the specified scopes
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);
是使用ASP.NET Core 2.0和MSAL 2的代码示例,有关详细说明,请阅读
README.md


您还可以单击获取代码示例,该示例根据Azure AD B2C对用户进行身份验证,并使用ASP.NET Core 2.1使用MSAL.NET获取访问令牌。

@L-Four,您提到的代码中实际上有一个分支已更新为MSAL的最新版本:

这么说来,当运行它时,我得到了一个未经授权的错误。所以我不确定这是怎么回事。但我确实得到了一个帐户。

已更新为使用MSAL v2.7。所使用的作用域不正确,因此示例现在使用正确的作用域,并返回一个访问令牌


“ApiScopes”:https://fabrikamb2c.onmicrosoft.com/helloapi/demo.read“

谢谢!但首先,当我使用ASP.NET Core 2.2时,这个OnAuthorizationCodeReceived在默认情况下已经被调用了?因为在startup.cs中,我看到AddAzureADB2C被调用,如果我是对的话,它会这样做。其次,我需要获取IAccount,而不是IUser,因为这是ASP.NET Core 2.2。。。。但是我从GetAccountsAsync接收null,这也导致AcquireTokenSilentAsync失败……我只是在问题中添加了一个额外的观察结果。