我需要从我的客户端应用程序访问受保护的 Web API(托管在 Azure 上)。 当我打开我的客户端应用程序时,我正在检索访问令牌,然后我将其添加到请求标头中,但 API 返回
401 unauthorized
.
public async Task<string> GetToken()
{
var authorizationUri = new Uri($@"https://login.microsoftonline.com/{AUTHORITY}");
var pca = PublicClientApplicationBuilder.Create(CLIENTID)
.WithAuthority(authorizationUri)
//.WithAuthority(AadAuthorityAudience.AzureAdAndPersonalMicrosoftAccount)
.WithRedirectUri(REDIRECTURL).Build();
// 2. GetAccounts
var accounts = await pca.GetAccountsAsync();
var accountToLogin = PublicClientApplication.OperatingSystemAccount;
try
{
// 3. AcquireTokenSilent
var authResult = await pca.AcquireTokenSilent(new[] { "api://..api-id../access_as_user" }, accountToLogin)
.ExecuteAsync();
return authResult.AccessToken;
}
catch (MsalUiRequiredException)
{
// 5. AcquireTokenInteractive
var authResult = await pca.AcquireTokenInteractive(new[] { "api://..api-id../access_as_user" })
.WithAccount(accountToLogin)
.ExecuteAsync();
return authResult.AccessToken;
}
}
public async Task<string> GetForecast()
{
var access = new ServiceAccess();
var token = await access.GetToken();
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token);
using HttpResponseMessage response = await client.GetAsync("https://my-api.azurewebsites.net/api/weatherforecast");
response.EnsureSuccessStatusCode();
...
}
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "mypolicy",
policy =>
{
policy.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod();
});
});
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options => builder.Configuration.Bind("AzureAd", options));
当我在 jwt.io 中检查令牌的内容时,我没有发现任何问题。
{
"aud": "my web API id",
"iss": "https://login.microsoftonline.com/my-tenant-id/v2.0",
"iat": 1675018002,
"nbf": 1675018002,
"exp": 1675022027,
"aio": "....",
"azp": "my web API id",
"azpacr": "0",
"idp": "live.com",
"name": "...",
"oid": "some guid",
"preferred_username": "[email protected]",
"rh": "???",
"scp": "access_as_user",
"sub": "???",
"tid": "my tenant id",
"uti": "???",
"ver": "2.0"
}
在 SO 中找到了一些类似的帖子,但它们似乎都没有提到我的问题
调试令牌问题的一种方法是在 AddJwtBearer 选项中启用以下标志:
/// <summary>
/// Defines whether the token validation errors should be returned to the caller.
/// Default set to true.
/// </summary>
public bool IncludeErrorDetails { get; set; } = true;
如果设置为 true,它将在响应头中包含更多错误详细信息:
HTTP/1.1 401 Unauthorized
Date: Sun, 02 Aug 2020 11:19:06 GMT
WWW-Authenticate: Bearer error="invalid_token", error_description="The signature is invalid"
另一种方法是查看 AddJwtBearer 的日志。
要访问日志文件,您可以将调试级别更改为 Microsoft.AspNetCore.Authentication 命名空间的调试或跟踪。如果您从 appsettings 配置日志记录,您可以使用:
{
"Logging": {
"LogLevel": {
"Default": "Warning",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.AspNetCore.Authentication": "Debug",
"Microsoft.AspNetCore.Authorization": "Trace"
}
}
}
为了补充这个答案,我写了一篇博客文章,详细介绍了这个主题: 解决 ASP.NET Core 中的 JwtBearer 身份验证问题