Ocelot 与 Azure Active Directory 身份验证 .Net Core 3.1 集成

CRa*_*sey 3 azure-active-directory api-gateway ocelot asp.net-core-3.1

背景:我的公司正在转向 API 网关来管理我们网络中的所有服务。目前,每项服务均使用 Azure AD 进行身份验证。一切都是单一租户,只允许公司用户。 问题:我的理解正确吗? 问题:当我调用 http:localhost:5000/authResource/get 时,我收到来自 Ocelot 的 401 响应。跟踪错误后,我发现当 Ocelot 身份验证中间件尝试使用 AzureADJwtBearer 方案进行身份验证时,我得到了 null。

我遵循了与 Ocelot 和 azure ad 相关的问题的建议,但即使遵循了这些建议,我也无法让任何东西发挥作用。(主要来自这个答案:How set up 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();
        }
Run Code Online (Sandbox Code Playgroud)

同样来自 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();
        }
Run Code Online (Sandbox Code Playgroud)

我的经过身份验证的资源的 ocelot.json 文件如下(出于安全原因更改了名称):

{
      "DownstreamPathTemplate": "/api/Controller/Get",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 5003
        }
      ],
      "UpstreamPathTemplate": "/authResource/get",
      "UpstreamHttpMethod": [ "GET" ],

      "AuthenticationOptions": {
        "AuthenticationProviderKey": "AzureADJwtBearer",
        "AllowedScopes": []
      }
    }
Run Code Online (Sandbox Code Playgroud)

为了巩固我对此的理解,我将使用 ocelot 配置中显示的示例 api 来完成一个示例。

我希望访问资源http://localhost:5003/api/Controller/Get,这是一个受保护的 API,这意味着如果我在 get 请求中提供授权标头,我只能从中获得响应。我通过 ocelot 网关向 URL http://localhost:5000/authResource/get发出请求(我在 localhost:5000 上托管 Ocelot)。Ocelot 认为需要进行身份验证才能访问此资源,因此它使用 AzureADJwtBearer 方案发出请求。我被重定向到微软登录。完成后,我会被发送回 Ocelot 应用程序,并附带一个访问令牌。Ocelot 获取此信息,创建 Auth 标头,最后调用http://localhost:5003/api/Controller/Get并返回结果。

CRa*_*sey 5

.Net Core 3.1 的工作示例

我最终使用 Microsoft.Identity.Web 库(当前版本位于https://github.com/AzureAD/microsoft-identity-web/tree/master/src/Microsoft.Identity.Web)来完成此工作

首先,我的 ocelot 配置文件 (ocelot.json):

{
  "ReRoutes": [
    {
      "DownstreamPathTemplate": "/myapp/api/{everything}",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        {
          "Host": "apphost.com",
          "Port": 443
        }
      ],
      "UpstreamPathTemplate": "/api/{everything}",
      "UpstreamHttpMethod": [ "GET", "POST" ],

      "AuthenticationOptions": {
        "AuthenticationProviderKey": "Bearer",
        "AllowedScopes": []
      }
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

请注意,AuthenticationProviderKey 的值为 Bearer。

我的 appsettings.json 文件包含我的 azure 配置:

"AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "mydomain.com",
    "TenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "ClientId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  }
Run Code Online (Sandbox Code Playgroud)

最后,我的 Startup.cs 文件包含类似的内容(为了简洁而减少)

public void ConfigureServices(IServiceCollection services)
        {
            services.AddProtectedWebApi(Configuration)
                .AddProtectedApiCallsWebApis(Configuration)
                .AddInMemoryTokenCaches();

            services.AddOcelot(Configuration);
            services.AddControllers();
        }

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                IdentityModelEventSource.ShowPII = true;
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });

            app.UseOcelot().Wait();

            app.UseAuthentication();
        }
Run Code Online (Sandbox Code Playgroud)

完成所有设置后,我可以传入使用我的 azure 凭据生成的不记名令牌,ocelot 网关将正确验证它。