'Invalid token' 将 Web API 与 Azure AD 验证的 Swagger 结合使用时
'Invalid token' when using webapi thru Swagger authenticated by Azure AD
我尝试在来自 swagger (Swashbuckle) 客户端的 WebApi (dotnet core 3.1) 上使用 AAD 身份验证。
在我的 Startup class 中,我配置如下:
// Configure authentication
services.AddAuthentication(AzureADDefaults.JwtBearerAuthenticationScheme)
.AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
我的 AzureAd 设置:
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"ClientId": "xxxx-xxxxx1b",
"Domain": "myoffice.onmicrosoft.com",
"TenantId": "xxxxx-xxxxa5",
"Scope": "api://xxxxxxxx-abc3cff48f1b/Full.Access",
"ScopeDescription": "Full Access"
},
...
services.AddSwaggerGen(c =>
{
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
{
Type = SecuritySchemeType.OAuth2,
In = ParameterLocation.Header,
Flows = new OpenApiOAuthFlows()
{
Implicit = new OpenApiOAuthFlow
{
TokenUrl = new Uri($"Configuration["AzureAd:Instance"]}/{Configuration["AzureAd:TenantId"]}/oauth2/v2.0/token"),
AuthorizationUrl = new Uri($"{Configuration["AzureAd:Instance"]}/{Configuration["AzureAd:TenantId"]}/oauth2/v2.0/authorize"),
Scopes =
{
{
Configuration["AzureAd:Scope"],Configuration["AzureAd:ScopeDescription"]
}
}
}
}
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
Array.Empty<string>()
}
});
});
在我的配置方法中:
app.UseSwaggerUI(c =>
{
c.RoutePrefix = string.Empty;
c.SwaggerEndpoint($"/swagger/{ApiVersion}/swagger.json", ApiName);
c.OAuthClientId(Configuration["AzureAd:ClientId"]);
c.OAuthScopeSeparator(" ");
});
Swagger 使用我的凭据正确登录到 AAD,当我使用受 [Authorize]
保护的路由时,令牌被正确发送到 API,我收到 401 错误并显示以下消息:
www-authenticate: Bearer error="invalid_token"error_description="The issuer 'https://login.microsoftonline.com/{tenantid}/v2.0' is invalid"
url https://login.microsoftonline.com/{tenantid}/v2.0
在 iss 部分的令牌中。
怎么了?
根据您的错误和您的代码,您没有告诉您的应用程序 ValidIssuer。所以你得到了错误。请在startup.cs
文件
的方法ConfigureServices
中添加以下代码
services.Configure<JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme, options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuers = new[] {
},
});
例如
为您的网站配置 Azure AD API。详情请参考document
一个。创建 Azure AD web api 应用程序
b。 Expose API
c。配置代码
- 配置文件
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"ClientId": "[Client_id-of-web-api-eg-2ec40e65-ba09-4853-bcde-bcb60029e596]",
"TenantId": "<your tenant id>"
},
- 在Stratup.cs
中添加如下代码
services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
.AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
services.Configure<JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme, options =>
{
options.Authority += "/v2.0";
options.TokenValidationParameters = new TokenValidationParameters
{
/**
* with the single-tenant application, you can configure your issuers
* with the multiple-tenant application, please set ValidateIssuer as false to disable issuer validation
*/
ValidIssuers = new[] {
$"https://sts.windows.net/{Configuration["AzureAD:TenantId"]}/",
$"https://login.microsoftonline.com/{Configuration["AzureAD:TenantId"]}/v2.0"
},
ValidAudiences = new[]
{
options.Audience,
$"api://{options.Audience}"
}
};
});
配置招摇。详情请参考blog.
一个。创建 Azure Web 应用程序
b。配置 API 权限。关于如何配置,可以参考document
c。代码
安装SDK
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.5.1" />
配置文件
"Swagger": {
"ClientId": ""
},
在ConfigureServices方法的Startup.cs中添加如下代码:
services.AddSwaggerGen(o =>
{
// Setup our document's basic info
o.SwaggerDoc("v1", new OpenApiInfo
{
Title = "Protected Api",
Version = "1.0"
});
// Define that the API requires OAuth 2 tokens
o.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows
{
Implicit = new OpenApiOAuthFlow
{
Scopes = new Dictionary<string, string>
{
{ "api://872ebcec-c24a-4399-835a-201cdaf7d68b/user_impersonation","allow user to access api"}
},
AuthorizationUrl = new Uri($"https://login.microsoftonline.com/{Configuration["AzureAD:TenantId"]}/oauth2/v2.0/authorize"),
TokenUrl = new Uri($"https://login.microsoftonline.com/{Configuration["AzureAD:TenantId"]}/oauth2/v2.0/token")
}
}
});
o.AddSecurityRequirement(new OpenApiSecurityRequirement{
{
new OpenApiSecurityScheme{
Reference = new OpenApiReference{
Id = "oauth2",
Type = ReferenceType.SecurityScheme
}
},new List<string>()
}
});
});
将以下代码添加到 Configure 方法中:
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.OAuthClientId(Configuration["Swagger:ClientId"]);
c.OAuthScopeSeparator(" ");
c.OAuthAppName("Protected Api");
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
测试
我尝试在来自 swagger (Swashbuckle) 客户端的 WebApi (dotnet core 3.1) 上使用 AAD 身份验证。 在我的 Startup class 中,我配置如下:
// Configure authentication
services.AddAuthentication(AzureADDefaults.JwtBearerAuthenticationScheme)
.AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
我的 AzureAd 设置:
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"ClientId": "xxxx-xxxxx1b",
"Domain": "myoffice.onmicrosoft.com",
"TenantId": "xxxxx-xxxxa5",
"Scope": "api://xxxxxxxx-abc3cff48f1b/Full.Access",
"ScopeDescription": "Full Access"
},
...
services.AddSwaggerGen(c =>
{
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
{
Type = SecuritySchemeType.OAuth2,
In = ParameterLocation.Header,
Flows = new OpenApiOAuthFlows()
{
Implicit = new OpenApiOAuthFlow
{
TokenUrl = new Uri($"Configuration["AzureAd:Instance"]}/{Configuration["AzureAd:TenantId"]}/oauth2/v2.0/token"),
AuthorizationUrl = new Uri($"{Configuration["AzureAd:Instance"]}/{Configuration["AzureAd:TenantId"]}/oauth2/v2.0/authorize"),
Scopes =
{
{
Configuration["AzureAd:Scope"],Configuration["AzureAd:ScopeDescription"]
}
}
}
}
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
Array.Empty<string>()
}
});
});
在我的配置方法中:
app.UseSwaggerUI(c =>
{
c.RoutePrefix = string.Empty;
c.SwaggerEndpoint($"/swagger/{ApiVersion}/swagger.json", ApiName);
c.OAuthClientId(Configuration["AzureAd:ClientId"]);
c.OAuthScopeSeparator(" ");
});
Swagger 使用我的凭据正确登录到 AAD,当我使用受 [Authorize]
保护的路由时,令牌被正确发送到 API,我收到 401 错误并显示以下消息:
www-authenticate: Bearer error="invalid_token"error_description="The issuer 'https://login.microsoftonline.com/{tenantid}/v2.0' is invalid"
url https://login.microsoftonline.com/{tenantid}/v2.0
在 iss 部分的令牌中。
怎么了?
根据您的错误和您的代码,您没有告诉您的应用程序 ValidIssuer。所以你得到了错误。请在startup.cs
文件
ConfigureServices
中添加以下代码
services.Configure<JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme, options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuers = new[] {
},
});
例如
为您的网站配置 Azure AD API。详情请参考document
一个。创建 Azure AD web api 应用程序
b。 Expose API
c。配置代码
- 配置文件
"AzureAd": { "Instance": "https://login.microsoftonline.com/", "ClientId": "[Client_id-of-web-api-eg-2ec40e65-ba09-4853-bcde-bcb60029e596]", "TenantId": "<your tenant id>" },
- 在Stratup.cs 中添加如下代码
services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme) .AddAzureADBearer(options => Configuration.Bind("AzureAd", options)); services.Configure<JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme, options => { options.Authority += "/v2.0"; options.TokenValidationParameters = new TokenValidationParameters { /** * with the single-tenant application, you can configure your issuers * with the multiple-tenant application, please set ValidateIssuer as false to disable issuer validation */ ValidIssuers = new[] { $"https://sts.windows.net/{Configuration["AzureAD:TenantId"]}/", $"https://login.microsoftonline.com/{Configuration["AzureAD:TenantId"]}/v2.0" }, ValidAudiences = new[] { options.Audience, $"api://{options.Audience}" } }; });
配置招摇。详情请参考blog.
一个。创建 Azure Web 应用程序
b。配置 API 权限。关于如何配置,可以参考document
c。代码
安装SDK
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.5.1" />
配置文件
"Swagger": { "ClientId": "" },
在ConfigureServices方法的Startup.cs中添加如下代码:
services.AddSwaggerGen(o => { // Setup our document's basic info o.SwaggerDoc("v1", new OpenApiInfo { Title = "Protected Api", Version = "1.0" }); // Define that the API requires OAuth 2 tokens o.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme { Type = SecuritySchemeType.OAuth2, Flows = new OpenApiOAuthFlows { Implicit = new OpenApiOAuthFlow { Scopes = new Dictionary<string, string> { { "api://872ebcec-c24a-4399-835a-201cdaf7d68b/user_impersonation","allow user to access api"} }, AuthorizationUrl = new Uri($"https://login.microsoftonline.com/{Configuration["AzureAD:TenantId"]}/oauth2/v2.0/authorize"), TokenUrl = new Uri($"https://login.microsoftonline.com/{Configuration["AzureAD:TenantId"]}/oauth2/v2.0/token") } } }); o.AddSecurityRequirement(new OpenApiSecurityRequirement{ { new OpenApiSecurityScheme{ Reference = new OpenApiReference{ Id = "oauth2", Type = ReferenceType.SecurityScheme } },new List<string>() } }); });
将以下代码添加到 Configure 方法中:
app.UseSwagger(); app.UseSwaggerUI(c => { c.OAuthClientId(Configuration["Swagger:ClientId"]); c.OAuthScopeSeparator(" "); c.OAuthAppName("Protected Api"); c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); });
测试