如何验证图形 API Microsoft JWT access_token并保护您的 API



场景:

我有一个 angular5 客户端应用程序,它使用 hello.js 使用用户的 Office 365 凭据对用户进行身份验证。

客户端代码:

hello.init({
msft: {
id: configuration.AppID,
oauth: {
version: 2,
auth: 'https://login.microsoftonline.com/' + configuration.TenantID + '/oauth2/v2.0/authorize'
},
scope_delim: ' ',
form: false
},
},
{ redirect_uri: configuration.redirecturl }
);
}

login() {
hello('msft').login({ scope: 'User.Read People.Read', display: 'popup' })
.then((authData: any) => {  // console.log(authData);
this.zone.run(() => {
// get profile
}

成功的响应是(出于安全原因进行了操作)

{  
"msft":{  
"access_token":"REMOVED TOKEN HERE",
"token_type":"Bearer",
"expires_in":3599,
"scope":"basic,User.Read,People.Read",
"state":"",
"session_state":"3b82898a-2b3f-445363f-89ae-d9696gg64ad3",
"client_id":"672330148-2bb43-3080-9eee-1f46311f789c",
"network":"msft",
"display":"popup",
"redirect_uri":"http://localhost:5653/",
"expires":15245366.218
}
}

解码access_token具有以下几个键:

页眉:

1. nonce(需要一些特殊处理,我找不到任何关于特殊处理的文档)

2. 典型值:智威汤逊

有效载荷:

"澳元": "https://graph.microsoft.com",

收到access_token后,我将向后端 API 发送每次调用的授权标头中的access_token。目标是验证令牌,并且仅在验证和授权access_token时发送成功的响应。如果不成功,则响应为 401 未授权。

用于验证 access_token、ASP .NET CORE 2、以下 (https://auth0.com/blog/securing-asp-dot-net-core-2-applications-with-jwts/) 的 API 代码

namespace JWT
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["Jwt:Issuer"],
ValidAudience = Configuration["Jwt:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
};
});
services.AddMvc();
}
}
}
// other methods
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseAuthentication();
app.UseMvc();
}

在appsettings.json中,我有:

{   "Jwt": {
"Key": "verySecretKey", **(I got the key from https://login.microsoftonline.com/common/discovery/keys with the kid value in access_token header)**
"Issuer": "https://sts.windows.net/49bcf059-afa8-4bf9-8470-fad0c9cce27d/",   } }

最后,我收到的错误是:"WWW 身份验证→持有者错误="invalid_token",error_description="找不到签名密钥">

我从这几天就被困在这里了,任何帮助都是救命恩人。

要点:

  1. 我试图在 jwt.io(https://nicksnettravels.builttoroam.com/post/2017/01/24/Verifying-Azure-Active-Directory-JWT-Tokens.aspx)中验证access_token,但我无法做到。

  2. 这里的澳元是 https://graph.microsoft.com,我不确定我是否需要以及为什么我需要将澳元更改为我的客户 ID。 我该怎么做?

  3. 代码中是否有问题,或者我需要调整请求标头令牌的方式。

如果您需要更多信息,请告诉我。

我试图在 jwt.io(https://nicksnettravels.builttoroam.com/post/2017/01/24/Verifying-Azure-Active-Directory-JWT-Tokens.aspx)中验证access_token,但我无法做到。

Microsoft图形 API 访问令牌的签名方式与我所看到的其他访问令牌不同。 您无需验证用于其他 API 的令牌,这是他们的工作。

这里的澳元是 https://graph.microsoft.com,我不确定我是否需要以及为什么我需要将澳元更改为我的客户 ID。 我该怎么做?

我不知道HelloJS,但是在使用response_type=id_token token进行身份验证后,您应该能够获得Id令牌。 然后,您需要将其附加到请求中。 它应该将你的客户端 ID 作为受众。

代码中是否有问题,或者我需要调整请求标头令牌的方式。

对我来说唯一突出的是你正在做很多不必要的配置。 基本上配置应该是:

.AddJwtBearer(o =>
{
o.Audience = "your-client-id";
o.Authority = "https://login.microsoftonline.com/your-tenant-id/v2.0";
})

处理程序将在启动时自动获取公共签名密钥。 在应用中对签名密钥进行硬编码并不是一个好主意,因为当 AAD 完成签名密钥滚动更新时,应用将中断。

我也花了很多时间试图验证它,但最重要的是你不能:

访问令牌是仅用于资源的不透明文本斑点。如果你是获取 Graph 令牌的客户端,请假设它是一个加密字符串,你永远不应该查看 - 有时它会是。我们为 Graph 使用他们知道如何验证的特殊令牌格式 - 如果访问令牌不适合你,则不应查看它们。(来源:https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/609)

您应该创建一个 ID 令牌,而不是使用访问令牌,这是一个常规的 JWT令牌,可以像任何其他 JWT 一样进行验证:

  1. 从Microsoft目录中获取公钥
  2. 验证签名、受众、颁发者等。

若要在登录后使用 MSAL API 获取 ID 令牌,可以执行以下操作(JavaScript 示例):

const { instance, accounts } = useMsal();
const request = {
scopes: ["User.Read"],
account: accounts[0]
};
const idToken = await instance.acquireTokenSilent(request).idToken;

有关ID令牌的更多信息,请查看:

https://learn.microsoft.com/en-us/azure/active-directory/develop/id-tokens

有关不透明代币的更多信息,请查看:

https://zitadel.com/blog/jwt-vs-opaque-tokens

是的,这需要一点时间才能解决。对于其他研究这个的人,这是我的理解。

不使用Microsoft图形 API 来保护 Web API。相反:

  1. 客户端继续使用 Microsoft 身份平台进行身份验证。

  2. 客户端使用生成的 JWT 访问令牌像往常一样调用 OAuth 2.0 流的 Web API

  3. Web API 使用 JwtBearerAuthenticationScheme,将权限设置为Microsoft身份平台。请参阅此示例并搜索 JwtBearerAuthenticationScheme。

  4. Web API 使用提供的访问令牌获取"代表"用户令牌。

  5. Web API 使用此"代表"令牌调用图形 API。此令牌的生存期与客户端获取的令牌不同,刷新必须单独处理。

这是此示例的一个非常提炼的版本。免责声明:我还没有将其付诸实践。

最新更新