Envoy實現.NET架構的閘道器(四)整合IdentityServer4實現OAuth2認證

chester·chen發表於2021-11-01

什麼是OAuth2認證

簡單說,OAuth 就是一種授權機制。資料的所有者告訴系統,同意授權第三方應用進入系統,獲取這些資料。系統從而產生一個短期的進入令牌(token),用來代替密碼,供第三方應用使用。而IdentityServer4就是一個開源的OAuth2認證系統。閘道器與IdentityServer4整合之後,我們可以避免為內部的每個微服務整合IdentityServer4,可以避免很多重複的工作,而這也是閘道器的一個重要優勢。

新建IdentityServer4服務

1.新增WebApi,並引用Nuget包IdentityServer4

2.新增校驗證書,其中的證書檔案通過openssl建立

     2.1安裝生成證書程式:https://slproweb.com/products/Win32OpenSSL.html(對應作業系統)

     2.2生成證書【找到安裝位置】

openssl req -newkey rsa:2048 -nodes -keyout chester.key -x509 -days 365 -out chester.cer

Country Name (2 letter code) [AU]:跳過所有步驟

openssl pkcs12 -export -in chester.cer -inkey chester.key -out chester.pfx

輸入密碼:123456 確認密碼:123456 即可

3.新增配置資訊

public class Config
    {
        public static IEnumerable<ApiResource> GetApiResources()
        {
            return new List<ApiResource>
              {
                new ApiResource("api1", "我的第一個API")
                {
                    UserClaims =
                    {
                        JwtClaimTypes.Audience
                    },
                    Scopes = new List<string>
                    {
                        "api"
                    },
                }
              };
        }
        public static IEnumerable<Client> GetClients()
        {
            return new List<Client>
            {
                new Client
                {
                    ClientId="client",//定義客戶端ID
                    ClientSecrets=
                    {
                        new Secret("secret".Sha256())//定義客戶端祕鑰
                    },
                    AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,//授權方式為使用者密碼模式授權,型別可參考GrantTypes列舉
                    AllowedScopes={ "api" }//允許客戶端訪問的範圍
                }
            };
        }

        public static IEnumerable<ApiScope> ApiScopes =>
            new ApiScope[] { new ApiScope("api") };

        public static IEnumerable<IdentityResource> GetIdentityResources()
        {
            return new IdentityResource[]
            {
                new IdentityResources.OpenId()
            };
        }
    }

4.注入IdentityServer4

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddIdentityServer()//註冊服務
              //.AddDeveloperSigningCredential()
              .AddSigningCredential(new X509Certificate2("chester.pfx","123456") )
              .AddInMemoryApiResources(Config.GetApiResources())//配置類定義的授權範圍
              .AddInMemoryClients(Config.GetClients())//配置類定義的授權客戶端
               .AddInMemoryApiScopes(Config.ApiScopes)
              .AddTestUsers(new List<TestUser> { new TestUser { Username = "Admin", Password = "123456", SubjectId = "001", IsActive = true } });//模擬測試使用者,這裡偷懶了,使用者可以單獨管理,最好不要直接在這裡New
            services.AddControllers();
        }

5.開啟IdentityServer4中介軟體

app.UseIdentityServer();//新增中介軟體

6.然後啟動IdentityServer4服務

配置Envoy

我們需要用到Envoy的envoy.filters.http.jwt_authn,需要注意的有以下幾點

  • Envoy的過濾器載入是自上而下的,因此我們需要將此過濾器放到envoy.filters.http.router前
  • 另外我們需要在配置檔案中配置jwt的jwks地址/.well-known/openid-configuration/jwks,jwks是JSON Web金鑰集—一種用於共享公鑰的JSON表示法,用於驗證JWT簽名
  • 並且我們需要配置ids4服務的cluster。

具體配置如下,需要注意的地方已標紅

admin:
  address:
    socket_address:
      protocol: TCP
      address: 0.0.0.0
      port_value: 9902
static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address:
        protocol: TCP
        address: 0.0.0.0
        port_value: 10000
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          scheme_header_transformation:
            scheme_to_overwrite: http
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                  host_rewrite_literal: 192.168.43.94
                  cluster: service_envoyproxy_io
          http_filters:
          - name: envoy.filters.http.jwt_authn
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication
              providers:
                jwt_provider:
                  issuer: "http://192.168.43.94:7000"
                  audiences:
                    - "api1"
                  forward: true
                  remote_jwks:
                    http_uri:
                      uri: "http://192.168.43.94:7000/.well-known/openid-configuration/jwks"
                      cluster: jwtserver
                      timeout: 5s
              rules:
                - match:
                    prefix: "/"
                  requires:
                    provider_name: jwt_provider
          - name: envoy.filters.http.router
  clusters:
  - name: jwtserver
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: jwtserver
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: 192.168.43.94
                port_value: 7000
  - name: service_envoyproxy_io
    connect_timeout: 30s
    type: strict_dns
    # Comment out the following line to test on v6 networks
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: service_envoyproxy_io
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: 192.168.43.94
                port_value: 5000

啟動envoy

docker run --rm -it -p 9902:9902 -p 10000:10000 -v D:/gateway/envoy/config/static/:/etc/envoy/ -v D:/gateway/envoy/logs:/logs envoyproxy/envoy-dev  -c /etc/envoy/envoy-jwt.yaml

驗證jwt

我們直接訪問http://192.168.43.94:10000/Name,不攜帶token,可以看到請求被拒絕,返回401

 下面我們呼叫ids4的/connect/token介面獲取token

將獲取到的token放到Name介面的Header裡,再次呼叫成功!!!

 

至此,我們通過Envoy+IdentityServer4實現了閘道器的JWT認證,可以節省內部微服務與IdentityServer4重複的整合工作,實現了統一處理認證邏輯。

相關文章