我在 .NET Core 中为我的组织构建了一个 api,并使用 PKCE 保护了 MSAL OAuth2 流背后的端点。我想做好准备,以防 api 应该被第 3 方访问。 api 本身可以通过 Bearer 令牌访问,但我也想保护 Swagger UI(访问 /swagger/index.html 应重定向到授权按钮使用的相同 OAuth2 流),以防止未经授权访问文档。
这是当前设置:
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using System.Net;
namespace WebAPI.SomeNamespace
{
public class SwaggerAzureAdAuthMiddleware
{
private readonly RequestDelegate next;
public SwaggerAzureAdAuthMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task InvokeAsync(HttpContext context)
{
if (context.Request.Path.StartsWithSegments("/swagger") && !context.User.Identity.IsAuthenticated)
{
await context.ChallengeAsync(JwtBearerDefaults.AuthenticationScheme);
return;
}
await next.Invoke(context);
}
}
public static class SwaggerAuthExtensions
{
public static IApplicationBuilder UseSwaggerAzureAdAuth(this IApplicationBuilder builder)
{
return builder.UseMiddleware<SwaggerAzureAdAuthMiddleware>();
}
}
}
Startup.cs 摘录
//...
public void ConfigureServices(IServiceCollection services)
{
//...
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(_configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddMicrosoftGraph(_configuration.GetSection("MicrosoftGraph"))
.AddInMemoryTokenCaches();
//...
}
public void Configure(IApplicationBuilder app)
{
//...
app.UseSwaggerAzureAdAuth();
app.UseSwagger();
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "API v1");
options.OAuthClientId(_configuration.GetValue<string>("AzureAd:ClientId"));
options.OAuthScopes(_configuration.GetValue<string>("AzureAd:Scopes"));
options.OAuthUsePkce();
});
//...
}
//...
这肯定是错误的,但不知道如何纠正。根据我收集的信息,
await context.ChallengeAsync()
应该触发services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
中指定的流程,但我可能误解了这一点,因为这条线在调试时似乎没有做任何事情。请帮忙。
Swashbuckle 内置了用于集成 Azure AD 身份验证方案的配置,以便我们可以直接通过 Swagger UI 测试受 Azure AD 保护的 API。我关注了这个博客并在我身边进行了测试,效果很好。
首先,我使用 VS 模板创建了一个新的 .net 8 Web api,并将身份验证类型选择为
Microsoft Identity Platform
,以便 API 将包含使用 AAD 来保护 API 的代码。接下来,我需要使用我的 AAD 配置修改 appsettings.json。现在我需要在请求标头中包含一个不记名令牌,以便我可以访问默认的 api 端点,否则我将收到 401 错误。
剩下的就是添加 swagger 配置。使用以下代码替换默认的
builder.Services.AddSwaggerGen();
。
builder.Services.AddSwaggerGen(c => {
c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebApplication1", Version = "v1" });
c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows()
{
Implicit = new OpenApiOAuthFlow()
{
AuthorizationUrl = new Uri("https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/authorize"),
TokenUrl = new Uri("https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token"),
Scopes = new Dictionary<string, string> {
{
"api://{client_id}/Tiny.Greet", "API permission description"
}
}
}
}
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement() {
{
new OpenApiSecurityScheme {
Reference = new OpenApiReference {
Type = ReferenceType.SecurityScheme,
Id = "oauth2"
},
Scheme = "oauth2",
Name = "oauth2",
In = ParameterLocation.Header
},
new List < string > ()
}
});
});
并使用下面的代码来替换默认的
app.UseSwaggerUI();
。
app.UseSwaggerUI(options =>
{
options.OAuthAppName("Swagger Client");
options.OAuthClientId("client_id");
options.OAuthClientSecret("client_secret");
options.OAuthUseBasicAuthenticationWithAccessCodeGrant();
});
在我上面的代码中,我有这样的 api 范围
api://client_id/Tiny.Greet
。这是我自己暴露的api权限。当我想通过 Azure AD 保护我的 API 时,我需要拥有这样的 API 权限。如果您对这部分不熟悉,可以参考本系列教程。
然后,当我转到 Swagger UI 并单击“授权”按钮时,我将看到一个像这样的对话框。单击“授权”按钮会将我重定向到 Microsoft 登录页面,我需要使用我的帐户登录。我将能够使用正确的不记名令牌来测试 API。