问题描述
我正在尝试使用 ASP.NET Core 2.0 创建一个 Web API 服务器,该服务器使用 azure ad v2 端点令牌授权.我还有一个 Angular 2 应用程序,在其中进行 office365 登录.我从那里得到一个令牌,然后向 Web API 服务器中的授权操作发送一个简单的请求.但是我的令牌没有通过授权检查,我收到 401 Unauthorized 响应.提供的描述是:
I am trying to create a Web API server using ASP.NET Core 2.0 which uses azure ad v2 endpoint token authorization. I also have an Angular 2 app where the office365 login happens. I get a token from there and then send a simple request to an authorized action in the Web API server. However my token doesn't pass the authorization checks and I get a 401 Unauthorized response. The description provided is:
Bearer error="invalid_token", error_description="找不到签名密钥"
Bearer error="invalid_token", error_description="The signature key was not found"
我解码了令牌,解码器也抛出了无效签名错误.以下是我用于配置和令牌授权的代码的重要部分:
I decoded the token and the decoder throws an invalid signature error as well. Here are the important parts of my code I use for configuration and token authorization:
Web API 服务器:
appsettings.json
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"ClientId": "my-registered-app-client-id",
},
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Warning"
}
},
"Console": {
"LogLevel": {
"Default": "Warning"
}
}
}
}
AzureAdAuthenticationBuilderExtensions.cs
public static class AzureAdServiceCollectionExtensions
{
public static AuthenticationBuilder AddAzureAdBearer(this AuthenticationBuilder builder)
=> builder.AddAzureAdBearer(_ => { });
public static AuthenticationBuilder AddAzureAdBearer(this AuthenticationBuilder builder, Action<AzureAdOptions> configureOptions)
{
builder.Services.Configure(configureOptions);
builder.Services.AddSingleton<IConfigureOptions<JwtBearerOptions>, ConfigureAzureOptions>();
builder.AddJwtBearer();
return builder;
}
private class ConfigureAzureOptions: IConfigureNamedOptions<JwtBearerOptions>
{
private readonly AzureAdOptions _azureOptions;
public ConfigureAzureOptions(IOptions<AzureAdOptions> azureOptions)
{
_azureOptions = azureOptions.Value;
}
public void Configure(string name, JwtBearerOptions options)
{
options.Audience = _azureOptions.ClientId;
options.Authority = $"{_azureOptions.Instance}common/v2.0";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
};
}
public void Configure(JwtBearerOptions options)
{
Configure(Options.DefaultName, options);
}
}
}
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddAzureAdBearer(options => Configuration.Bind("AzureAd", options));
services.AddMvc();
services.AddCors(options =>
{
options.AddPolicy("AllowAllOrigins",
builder =>
{
builder.AllowAnyMethod().AllowAnyHeader().AllowAnyOrigin();
});
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors("AllowAllOrigins");
app.UseAuthentication();
app.UseMvc();
}
}
下面是我在 Angular2 应用中用来进行身份验证的代码:
import { Injectable } from '@angular/core';
import { Headers } from '@angular/http';
import * as hello from 'hellojs/dist/hello.all.js';
import * as MicrosoftGraph from "@microsoft/microsoft-graph-types";
import * as MicrosoftGraphClient from "@microsoft/microsoft-graph-client";
import { Configs } from "../../../shared/configs"
@Injectable()
export class HttpService {
url = `https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=${Configs.appId}&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F&response_mode=query&scope=openid%20offline_access%20https%3A%2F%2Fgraph.microsoft.com%2Fmail.read&state=12345`;
getAccessToken() {
const msft = hello('msft').getAuthResponse();
const accessToken = msft.access_token;
return accessToken;
}
getClient(): MicrosoftGraphClient.Client
{
var client = MicrosoftGraphClient.Client.init({
authProvider: (done) => {
done(null, this.getAccessToken()); //first parameter takes an error if you can't get an access token
},
defaultVersion: 'v2.0'
});
return client;
}
}
当从端点返回令牌时,我会向我的 Web API 服务器上的有效端点发送请求.
When a token is returned from the endpoint I send a request to a valid endpoint on my Web API server.
重要提示:我在 Web API 和 Angular 应用程序中使用相同的 AppId,因为 AzureAd v2.0 端点需要它.
我的意思是,我认为我做的一切都是照本宣科,但显然缺少一些东西.如果有人能告诉我我在配置中做错了什么,我将不胜感激!
My point is that I think I'm doing everything by the book but there is obviously something missing. If anyone could tell me what I did wrong in my configuration, I'd be immeasurably grateful!
解码令牌的aud属性为:
aud property of decoded token is:
https://graph.microsoft.com
推荐答案
在评论中经过不那么简短的讨论后,问题得到了解决.
After a not-so-short discussion in the comments the issue was resolved.
讨论的要点:
- 访问令牌包含一个
aud
声明,其值为https://graph.microsoft.com
,这意味着该令牌适用于 Microsoft Graph API,不是他们的 API - 需要在 https://apps.dev.microsoft.com/,之后应用需要使用类似于
api://25f66106-edd6-4724-ae6f-3a204cfd9f63/access_as_user
的scope
请求访问令牌李>
- The access token contained an
aud
claim with the value ofhttps://graph.microsoft.com
, which means the token is meant for the Microsoft Graph API, not their API - A Web API needed to be registered at https://apps.dev.microsoft.com/, after which the app needed to ask for an access token using a
scope
similar to:api://25f66106-edd6-4724-ae6f-3a204cfd9f63/access_as_user
因此,请确保 aud
声明包含 API 的客户端 ID 或应用 ID URI.这意味着它适用于您的 API.
So make sure that the aud
claim contains the client ID or app ID URI for your API. That means it is meant for your API.
令牌还需要包含必要的范围.
The token also needs to contain the necessary scopes.
从 AAD 请求访问令牌时,请确保指定正确的范围.
When asking for an access token from AAD, make sure you specify the correct scopes.
此外,如果您使用的是 v1 端点,请确保使用 ADAL,而不是 MSAL.在 v1 中,您还必须使用 resource
而不是范围,它的值必须设置为 API 的客户端 ID 或应用 ID URI.
Also, if you are using the v1 endpoints, make sure to use ADAL, not MSAL. In v1 also instead of scope, you have to use resource
, which must have a value set to either the client ID or app ID URI of the API.
这篇关于ASP.NET Core 2.0 Web API Azure Ad v2 令牌授权不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!