无法使用 asp.net 核心中的 MSAL 1.1.0-preview 通过授权代码获取 AccessToken
Failed to get AccessToken via authorization code using MSAL 1.1.0-preview in asp.net core
我按照下面的官方步骤尝试了场景“web app calling a Web API in Azure Ad B2C”,唯一的区别是我使用的是Asp.Net核心。我正在使用 AuthorizationCode 获取访问令牌,但它总是 returns 带有 id 令牌和 NULL 访问令牌.
- Create an Azure AD B2C tenant。
- Register a web api.
- Register a web app.
- Set up policies.
- Grant the web app permissions to use the web api.
我的代码:
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
AuthenticationScheme = OpenIdConnectDefaults.AuthenticationScheme,
AutomaticChallenge = true,
ClientId = aadB2cSettings.ClientId,
MetadataAddress = $"{aadB2cSettings.Instance}{aadB2cSettings.Tenant}/v2.0/.well-known/openid-configuration?p={aadB2cSettings.B2cSignUpOrSignInPolicy}",
PostLogoutRedirectUri = aadB2cSettings.RedirectUrl,
ResponseType = OpenIdConnectResponseType.CodeIdToken,
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name"
},
Events = new OpenIdConnectEvents
{
OnAuthorizationCodeReceived = async context =>
{
var authCode = context.TokenEndpointRequest.Code;
var b2cAuthority = $"{aadB2cSettings.Instance}tfp/{aadB2cSettings.Tenant}/{aadB2cSettings.B2cSignUpOrSignInPolicy}/v2.0/.well-known/openid-configuration";
var cca = new ConfidentialClientApplication(
aadB2cSettings.ClientId,
b2cAuthority,
aadB2cSettings.RedirectUrl,
new ClientCredential(aadB2cSettings.ClientSecret),
new TokenCache(),
null);
try
{
var authResult = await cca.AcquireTokenByAuthorizationCodeAsync(authCode, new[] { "https://hulab2c.onmicrosoft.com/b2cdemo/all" });
context.HandleCodeRedemption(authResult.AccessToken, authResult.IdToken);
}
catch (Exception ex)
{
throw ex;
}
}
},
使用fiddler抓取请求,是:
POST
https://login.microsoftonline.com/hulab2c.onmicrosoft.com/oauth2/v2.0/token?p=b2c_1_signuporsignin
HTTP/1.1
请求正文:
client_id=1ff91f47-08ee-4973-83f4-379ad7e0679c&client_info=1&client_secret=......&scope=https%3A%2F%2Fhulab2c.onmicrosoft.com%2Fb2cdemo%2Fall+offline_access+openid+profile&grant_type=authorization_code&code=......&redirect_uri=https%3A%2F%2Flocalhost%3A44383%2F
Return:
{"id_token":"......","token_type":"Bearer","not_before":1494494423,"client_info":"......","scope":""}
所以只有 id 令牌,没有访问令牌。但是我们应该在这里获取访问令牌,对吗?
https://github.com/Azure-Samples/active-directory-b2c-dotnet-webapp-and-webapi/issues/4 Microsoft 已重现该问题并正在修复
终于找到我失败的原因:获取AuthorizationCode的请求不包含目标范围。反映在代码中,对于aspnetcore中的OpenIdConnectOption,Scope参数是只读的,默认值为"opened profile"。
Scope is readonly in OpenIdConnectOption
所以默认发送的授权码请求是:
因此,使用此授权码响应获取令牌,即使我们在令牌请求中设置了正确的范围,我们仍然无法获取访问码,而只能获取 ID 令牌,因为提供的授权码仅用于 "openid profile".
要解决此问题,我们还需要将目标网络 api 范围添加到授权代码中。这是如何修复代码:
Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProvider = context =>
{
context.ProtocolMessage.Scope += $" offline_access {myapiscope}";
return Task.FromResult(0);
},
......
}
在AspNet中,我们不需要这样做,因为它的作用域不像aspnetcore那样只读,可以直接设置:
new OpenIdConnectAuthenticationOptions
{
......
Scope = $"openid profile offline_access {ReadTasksScope} {WriteTasksScope}"
}
我按照下面的官方步骤尝试了场景“web app calling a Web API in Azure Ad B2C”,唯一的区别是我使用的是Asp.Net核心。我正在使用 AuthorizationCode 获取访问令牌,但它总是 returns 带有 id 令牌和 NULL 访问令牌.
- Create an Azure AD B2C tenant。
- Register a web api.
- Register a web app.
- Set up policies.
- Grant the web app permissions to use the web api.
我的代码:
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
AuthenticationScheme = OpenIdConnectDefaults.AuthenticationScheme,
AutomaticChallenge = true,
ClientId = aadB2cSettings.ClientId,
MetadataAddress = $"{aadB2cSettings.Instance}{aadB2cSettings.Tenant}/v2.0/.well-known/openid-configuration?p={aadB2cSettings.B2cSignUpOrSignInPolicy}",
PostLogoutRedirectUri = aadB2cSettings.RedirectUrl,
ResponseType = OpenIdConnectResponseType.CodeIdToken,
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name"
},
Events = new OpenIdConnectEvents
{
OnAuthorizationCodeReceived = async context =>
{
var authCode = context.TokenEndpointRequest.Code;
var b2cAuthority = $"{aadB2cSettings.Instance}tfp/{aadB2cSettings.Tenant}/{aadB2cSettings.B2cSignUpOrSignInPolicy}/v2.0/.well-known/openid-configuration";
var cca = new ConfidentialClientApplication(
aadB2cSettings.ClientId,
b2cAuthority,
aadB2cSettings.RedirectUrl,
new ClientCredential(aadB2cSettings.ClientSecret),
new TokenCache(),
null);
try
{
var authResult = await cca.AcquireTokenByAuthorizationCodeAsync(authCode, new[] { "https://hulab2c.onmicrosoft.com/b2cdemo/all" });
context.HandleCodeRedemption(authResult.AccessToken, authResult.IdToken);
}
catch (Exception ex)
{
throw ex;
}
}
},
使用fiddler抓取请求,是:
POST https://login.microsoftonline.com/hulab2c.onmicrosoft.com/oauth2/v2.0/token?p=b2c_1_signuporsignin HTTP/1.1
请求正文:
client_id=1ff91f47-08ee-4973-83f4-379ad7e0679c&client_info=1&client_secret=......&scope=https%3A%2F%2Fhulab2c.onmicrosoft.com%2Fb2cdemo%2Fall+offline_access+openid+profile&grant_type=authorization_code&code=......&redirect_uri=https%3A%2F%2Flocalhost%3A44383%2F
Return:
{"id_token":"......","token_type":"Bearer","not_before":1494494423,"client_info":"......","scope":""}
所以只有 id 令牌,没有访问令牌。但是我们应该在这里获取访问令牌,对吗?
https://github.com/Azure-Samples/active-directory-b2c-dotnet-webapp-and-webapi/issues/4 Microsoft 已重现该问题并正在修复
终于找到我失败的原因:获取AuthorizationCode的请求不包含目标范围。反映在代码中,对于aspnetcore中的OpenIdConnectOption,Scope参数是只读的,默认值为"opened profile"。 Scope is readonly in OpenIdConnectOption
所以默认发送的授权码请求是:
因此,使用此授权码响应获取令牌,即使我们在令牌请求中设置了正确的范围,我们仍然无法获取访问码,而只能获取 ID 令牌,因为提供的授权码仅用于 "openid profile".
要解决此问题,我们还需要将目标网络 api 范围添加到授权代码中。这是如何修复代码:
Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProvider = context =>
{
context.ProtocolMessage.Scope += $" offline_access {myapiscope}";
return Task.FromResult(0);
},
......
}
在AspNet中,我们不需要这样做,因为它的作用域不像aspnetcore那样只读,可以直接设置:
new OpenIdConnectAuthenticationOptions
{
......
Scope = $"openid profile offline_access {ReadTasksScope} {WriteTasksScope}"
}