Ocelot簡易教程(五)之集成IdentityServer認證以及授權

Ocelot簡易教程目錄

  1. Ocelot簡易教程(一)之Ocelot是什麼
  2. Ocelot簡易教程(二)之快速開始1
  3. Ocelot簡易教程(二)之快速開始2
  4. Ocelot簡易教程(三)之主要特性及路由詳解
  5. Ocelot簡易教程(四)之請求聚合以及服務發現
  6. Ocelot簡易教程(五)之集成IdentityServer認證以及授權
  7. Ocelot簡易教程(六)之重寫配置文件存儲方式並優化響應數據
  8. Ocelot簡易教程(七)之配置文件數據庫存儲插件源碼解析

最近比較懶,所以隔了N天才來繼續更新第五篇Ocelot簡易教程,本篇教程會先簡單介紹下官方文檔記錄的內容然後在前幾篇文檔代碼的基礎上進行實例的演示。目的是爲了讓小白也能按照步驟把代碼跑起來。當然,在開始之前你要對IdentityServer有一定的瞭解,並且能夠進行IdentityServer的集成,如果你還不會集成IdentityServer的話還是先看看我的這篇Asp.NetCoreWebApi圖片上傳接口(二)集成IdentityServer4授權訪問(附源碼)文章吧。裏面有一步一步的集成IdentityServer的實例。

好了,廢話說完了,那就讓我們開始進入今天的主題吧!Ocelot認證與授權。

概念表述

認證

爲了驗證ReRoutes並隨後使用Ocelot的任何基於聲明的功能,例如授權或使用令牌中的值修改請求。 用戶必須像往常一樣在他們的Startup.cs中註冊認證服務,惟一的不同是他們需要給每個認證註冊提供一個方案,例如

<span style="color:#333333"><code><span style="color:#0000ff">public</span> <span style="color:#0000ff">void</span> <span style="color:#a31515">ConfigureServices</span>(IServiceCollection services)
{
    <span style="color:#0000ff">var</span> authenticationProviderKey = <span style="color:#a31515">"OcelotKey"</span>;

    services.AddAuthentication()
        .AddJwtBearer(authenticationProviderKey, x =>
        {
        });
}</code></span>

在此示例中,OcelotKey是此提供程序已註冊的方案。然後我們將其映射到配置中的ReRoute,例如

<span style="color:#333333"><code><span style="color:#a31515">"ReRoutes"</span>: [
    {
      <span style="color:#a31515">"DownstreamPathTemplate"</span>: <span style="color:#a31515">"/api/{everything}"</span>,
      <span style="color:#a31515">"DownstreamScheme"</span>: <span style="color:#a31515">"http"</span>,
      <span style="color:#a31515">"DownstreamHostAndPorts"</span>: [
        {
          <span style="color:#a31515">"Host"</span>: <span style="color:#a31515">"localhost"</span>,
          <span style="color:#a31515">"Port"</span>: <span style="color:#000000">1001</span>
        },
        {
          <span style="color:#a31515">"Host"</span>: <span style="color:#a31515">"localhost"</span>,
          <span style="color:#a31515">"Port"</span>: <span style="color:#000000">1002</span>
        }
      ],
      <span style="color:#a31515">"UpstreamPathTemplate"</span>: <span style="color:#a31515">"/{everything}"</span>,
      <span style="color:#a31515">"UpstreamHttpMethod"</span>: [ <span style="color:#a31515">"Get"</span>, <span style="color:#a31515">"Post"</span> ],
      <span style="color:#a31515">"LoadBalancerOptions"</span>: {
        <span style="color:#a31515">"Type"</span>: <span style="color:#a31515">"RoundRobin"</span>
      },
      <span style="color:#a31515">"AuthenticationOptions"</span>: {
        <span style="color:#a31515">"AuthenticationProviderKey"</span>: <span style="color:#a31515">"OcelotKey"</span>,
        <span style="color:#a31515">"AllowedScopes"</span>: []
      }
    }
  ]</code></span>

當Ocelot運行時,它將查看此ReRoutes中 AuthenticationOptions節點下面的AuthenticationProviderKey並檢查是否有使用給定密鑰註冊的身份驗證提供程序。如果沒有,那麼Ocelot不會啓動,如果有的話ReRoute將在執行時使用該提供者。

如果對ReRoute進行了身份驗證,則Ocelot將在執行身份驗證中間件時調用與其關聯的認證方案。如果請求失敗,則認證Ocelot返回http的狀態代碼爲401即未授權狀態。

JWT令牌

如果您想使用JWT令牌進行身份驗證,可能來自OAuth之類的提供程序,您可以正常註冊您的身份驗證中間件,例如

<span style="color:#333333"><code><span style="color:#0000ff">public</span> <span style="color:#0000ff">void</span> <span style="color:#a31515">ConfigureServices</span>(IServiceCollection services)
{
    <span style="color:#0000ff">var</span> authenticationProviderKey = <span style="color:#a31515">"OcelotKey"</span>;

    services.AddAuthentication()
        .AddJwtBearer(authenticationProviderKey, x =>
        {
            x.Authority = <span style="color:#a31515">"test"</span>;
            x.Audience = <span style="color:#a31515">"test"</span>;
        });

    services.AddOcelot();
}</code></span>

然後將身份驗證提供程序密鑰映射到配置中的ReRoute,例如

<span style="color:#333333"><code><span style="color:#a31515">"ReRoutes"</span>: [
    {
      <span style="color:#a31515">"DownstreamPathTemplate"</span>: <span style="color:#a31515">"/api/{everything}"</span>,
      <span style="color:#a31515">"DownstreamScheme"</span>: <span style="color:#a31515">"http"</span>,
      <span style="color:#a31515">"DownstreamHostAndPorts"</span>: [
        {
          <span style="color:#a31515">"Host"</span>: <span style="color:#a31515">"localhost"</span>,
          <span style="color:#a31515">"Port"</span>: <span style="color:#000000">1001</span>
        },
        {
          <span style="color:#a31515">"Host"</span>: <span style="color:#a31515">"localhost"</span>,
          <span style="color:#a31515">"Port"</span>: <span style="color:#000000">1002</span>
        }
      ],
      <span style="color:#a31515">"UpstreamPathTemplate"</span>: <span style="color:#a31515">"/{everything}"</span>,
      <span style="color:#a31515">"UpstreamHttpMethod"</span>: [ <span style="color:#a31515">"Get"</span>, <span style="color:#a31515">"Post"</span> ],
      <span style="color:#a31515">"LoadBalancerOptions"</span>: {
        <span style="color:#a31515">"Type"</span>: <span style="color:#a31515">"RoundRobin"</span>
      },
      <span style="color:#a31515">"AuthenticationOptions"</span>: {
        <span style="color:#a31515">"AuthenticationProviderKey"</span>: <span style="color:#a31515">"OcelotKey"</span>,
        <span style="color:#a31515">"AllowedScopes"</span>: []
      }
    }
  ]</code></span>

Identity Server Bearer Tokens認證

接下來上今天的主角了。identityServer認證方式。爲了使用IdentityServer承載令牌,請按照慣例在ConfigureServices 中使用方案(密鑰)註冊您的IdentityServer服務。 如果您不明白如何操作,請訪問IdentityServer文檔。或者查看我的這篇Asp.NetCoreWebApi圖片上傳接口(二)集成IdentityServer4授權訪問(附源碼)文章。

<span style="color:#333333"><code> <span style="color:#0000ff">var</span> authenticationProviderKey = <span style="color:#a31515">"OcelotKey"</span>;
            <span style="color:#0000ff">var</span> identityServerOptions = <span style="color:#0000ff">new</span> IdentityServerOptions();
            Configuration.Bind(<span style="color:#a31515">"IdentityServerOptions"</span>, identityServerOptions);
            services.AddAuthentication(identityServerOptions.IdentityScheme)
                .AddIdentityServerAuthentication(authenticationProviderKey, options =>
                {
                    options.RequireHttpsMetadata = <span style="color:#a31515">false</span>; <span style="color:green">//是否啓用https</span>
                    options.Authority = <span style="color:#a31515">$"http://<span style="color:#a31515">{identityServerOptions.ServerIP}</span>:<span style="color:#a31515">{identityServerOptions.ServerPort}</span>"</span>;<span style="color:green">//配置授權認證的地址</span>
                    options.ApiName = identityServerOptions.ResourceName; <span style="color:green">//資源名稱,跟認證服務中註冊的資源列表名稱中的apiResource一致</span>
                    options.SupportedTokens = SupportedTokens.Both;
                }
                );
            services.AddOcelot()<span style="color:green">//注入Ocelot服務</span>
                    .AddConsul();</code></span>

然後將身份驗證提供程序密鑰映射到配置中的ReRoute,例如

<span style="color:#333333"><code><span style="color:#a31515">"ReRoutes"</span>: [
    {
      <span style="color:#a31515">"DownstreamPathTemplate"</span>: <span style="color:#a31515">"/api/{everything}"</span>,
      <span style="color:#a31515">"DownstreamScheme"</span>: <span style="color:#a31515">"http"</span>,
      <span style="color:#a31515">"DownstreamHostAndPorts"</span>: [
        {
          <span style="color:#a31515">"Host"</span>: <span style="color:#a31515">"localhost"</span>,
          <span style="color:#a31515">"Port"</span>: <span style="color:#000000">1001</span>
        },
        {
          <span style="color:#a31515">"Host"</span>: <span style="color:#a31515">"localhost"</span>,
          <span style="color:#a31515">"Port"</span>: <span style="color:#000000">1002</span>
        }
      ],
      <span style="color:#a31515">"UpstreamPathTemplate"</span>: <span style="color:#a31515">"/{everything}"</span>,
      <span style="color:#a31515">"UpstreamHttpMethod"</span>: [ <span style="color:#a31515">"Get"</span>, <span style="color:#a31515">"Post"</span> ],
      <span style="color:#a31515">"LoadBalancerOptions"</span>: {
        <span style="color:#a31515">"Type"</span>: <span style="color:#a31515">"RoundRobin"</span>
      },
      <span style="color:#a31515">"AuthenticationOptions"</span>: {
        <span style="color:#a31515">"AuthenticationProviderKey"</span>: <span style="color:#a31515">"OcelotKey"</span>,
        <span style="color:#a31515">"AllowedScopes"</span>: []
      }
    }
  ]</code></span>

允許訪問的範圍(Allowed Scopes)

如果將範圍添加到AllowedScopes,Ocelot將獲得類型範圍的所有用戶聲明(從令牌中),並確保用戶具有列表中的所有範圍。

這是一種基於範圍限制對ReRoute訪問的方式。(我也沒用過這種方式,感覺有點類似IdentityServer Scope的概念)

實例演示集成IdentityServer

  1. 新建一個OcelotDemo.Auth asp.net core web api項目

  2. 項目進行IdentityServer服務端相關的配置,這裏爲了演示的方便採用硬編碼的方式進行的配置。具體配置可以參考Asp.NetCoreWebApi圖片上傳接口(二)集成IdentityServer4授權訪問(附源碼)這篇文章

  3. 在網關項目OcelotDemo中添加Nuget包

    Install-Package IdentityServer4.AccessTokenValidation   
  4. 在OcelotDemo項目中的Startup.cs中加入identityServer驗證,如下所示:

    var authenticationProviderKey = "OcelotKey";
                var identityServerOptions = new IdentityServerOptions();
                Configuration.Bind("IdentityServerOptions", identityServerOptions);
                services.AddAuthentication(identityServerOptions.IdentityScheme)
                    .AddIdentityServerAuthentication(authenticationProviderKey, options =>
                    {
                        options.RequireHttpsMetadata = false; //是否啓用https
                        options.Authority = $"http://{identityServerOptions.ServerIP}:{identityServerOptions.ServerPort}";//配置授權認證的地址
                        options.ApiName = identityServerOptions.ResourceName; //資源名稱,跟認證服務中註冊的資源列表名稱中的apiResource一致
                        options.SupportedTokens = SupportedTokens.Both;
                    }
                    );
                services.AddOcelot()//注入Ocelot服務
                        .AddConsul();
  5. 在ocelot.json中需要加入驗證的ReRoute中,修改爲如下的配置代碼:

    "ReRoutes": [
        {
          "DownstreamPathTemplate": "/api/{everything}",
          "DownstreamScheme": "http",
          "DownstreamHostAndPorts": [
            {
              "Host": "localhost",
              "Port": 1001
            },
            {
              "Host": "localhost",
              "Port": 1002
            }
          ],
          "UpstreamPathTemplate": "/{everything}",
          "UpstreamHttpMethod": [ "Get", "Post" ],
          "LoadBalancerOptions": {
            "Type": "RoundRobin"
          },
          "AuthenticationOptions": {
            "AuthenticationProviderKey": "OcelotKey",
            "AllowedScopes": []
          }
        }
      ]
  6. 打開PostMan測試一下代碼吧,首先訪問一下http://localhost:1000/values 這時候返回的結果是401未授權的狀態,如下圖所示:

    1539780575952

  7. 然後訪問我們上面新建的IdentityServer服務器並獲取Token。如下圖所示配置對應的參數進行獲取:

    1539780272769

  8. 然後使用我們獲取到的access_token進行Ocelot網關接口的訪問,如下所示進行配置:

    1539780805247

    可以看到結果返回了200代碼,並且結果在Good以及Order之間進行切換。因爲Ocelot.json文件中對路由進行了RoundRobin的負載均衡的策略。

授權

Ocelot支持基於聲明的授權,該授權在身份驗證後運行。這意味着如果您有要授權的Url,則可以將以下內容添加到ReRoute配置中。

<span style="color:#333333"><code><span style="color:#a31515">"RouteClaimsRequirement"</span>: {
    <span style="color:#a31515">"UserType"</span>: <span style="color:#a31515">"registered"</span>
}</code></span>

在此示例中,當調用授權中間件時,Ocelot將檢查用戶是否具有聲明類型UserType以及是否已註冊該聲明的值。如果不是,則用戶將不被授權,並且將響應403禁止訪問的狀態碼。

當然這種授權的方式在大部分業務場景中都是不適用的,需要自己重寫Ocelot的中間件才能實現。通過Ocelot中間件的重寫你可以實現自己的授權邏輯,如果你還有限流的需求,比如說對每個客戶端進行不同的限流策略。比方說,有三個客戶端A,B,C。訪問相同的URL,但是我們要控制A,每分鐘只能訪問10次,B每分鐘能訪問20次,而C不允許訪問。針對這個場景Ocelot卻沒有相關的實現。但是我們可以通過重寫Ocelot中間件來實現它。由於篇幅有限,所以今天就不進行介紹了。但是我會抽時間進行相關的實現,並分享給大家。

源碼

本篇博文的源碼已經上傳到Github。可以進行參考。https://github.com/yilezhu/OcelotDemo

總結

本文先大致介紹一下Ocelot如何集成認證授權,然後通過實例進行了IdentityServer集成的演示,希望能對大家有一定的參考作用。當然文中也提到了,應對複雜的授權以及限流需要自行重寫Ocelot中間件進行實現。具體如何實現呢,我會盡快分享給大家。同樣的通過重寫Ocelot中間件我們還可以把ocelot.json的配置信息存儲到數據庫並緩存到Redis中!最後,感謝大家的閱讀!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章