背景:我的公司正在迁移到 API 网关来管理我们网络中的所有服务。每个服务当前都使用 azure AD 进行身份验证。一切都是单租户,只允许公司用户。 问:我理解正确吗? 问题:当我调用 http:localhost:5000/authResource/get 时,我收到了来自 Ocelot 的 401 响应。跟踪错误后,我看到当 Ocelot 身份验证中间件尝试使用 AzureADJwtBearer 方案进行身份验证时,我返回 null。
我遵循了与 Ocelot 和 azure ad 相关的问题的建议,但即使遵循这些建议,我也无法进行任何工作。(主要来自这个答案:How setup Ocelot Api Gateway with Azure Active Directory)我想我可能误解了身份验证应该如何工作。我目前的理解是,我告诉 Ocelot 使用 AzureADJwtBearer 方案对我的一个 API 进行身份验证。在我的配置中,我有该特定 api 设置的信息(ClientId、TenantId 等)。
一旦我调用了路由,我希望 Ocelot 会调用 Microsoft 以开始身份验证。在这一点上,我期望与 API 提供的流程相同,即我拨打电话并获取 Microsoft 登录页面,然后在我输入用户名和密码后将我重定向回应用程序。
在将我重定向回 Ocelot 后,我猜(这是我模糊的部分),我希望 ocelot 存储 Microsoft 为我刚刚请求的特定资源发回的访问令牌。然后我希望 ocelot 将令牌附加到 Auth 标头,然后发送对我最初要求的资源的请求。
为了澄清这一点,我将包含我的启动文件和我的 ocelot.json 文件的代码。来自 Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddProtectedWebApi(Configuration)
.AddProtectedApiCallsWebApis(Configuration)
.AddInMemoryTokenCaches();
services.AddOcelot(Configuration);
services.AddControllers();
}
同样来自 Startup.cs
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseOcelot().Wait();
app.UseAuthentication();
}
我的已验证资源的 ocelot.json 文件如下(出于安全原因更改了名称):
{
"DownstreamPathTemplate": "/api/Controller/Get",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5003
}
],
"UpstreamPathTemplate": "/authResource/get",
"UpstreamHttpMethod": [ "GET" ],
"AuthenticationOptions": {
"AuthenticationProviderKey": "AzureADJwtBearer",
"AllowedScopes": []
}
}
为了巩固我对此的理解,我将通过一个示例,使用 ocelot 配置中显示的示例 api。
我希望访问资源http://localhost:5003/api/Controller/Get,这是一个受保护的 API,这意味着如果我在获取请求中提供授权标头,我只能从中获得响应。我通过我的 ocelot 网关向 url http://localhost:5000/authResource/get发出请求(我在 localhost:5000 上托管 Ocelot)。Ocelot 发现它需要进行身份验证才能访问此资源,因此它使用 AzureADJwtBearer 方案发出请求。我被重定向到微软登录。完成后,我会带着访问令牌返回到 Ocelot 应用程序。Ocelot 接受此操作,创建 Auth 标头,最后调用http://localhost:5003/api/Controller/Get并返回结果。