Envoy实现.NET架构的网关(四)集成IdentityServer4实现OAuth2认证

  • A+
所属分类:.NET技术
摘要

简单说,OAuth 就是一种授权机制。数据的所有者告诉系统,同意授权第三方应用进入系统,获取这些数据。系统从而产生一个短期的进入令牌(token),用来代替密码,供第三方应用使用。而IdentityServer4就是一个开源的OAuth2认证系统。网关与IdentityServer4集成之后,我们可以避免为内部的每个微服务集成IdentityServer4,可以避免很多重复的工作,而这也是网关的一个重要优势。


什么是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实现.NET架构的网关(四)集成IdentityServer4实现OAuth2认证

配置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

Envoy实现.NET架构的网关(四)集成IdentityServer4实现OAuth2认证

 下面我们调用ids4的/connect/token接口获取token

Envoy实现.NET架构的网关(四)集成IdentityServer4实现OAuth2认证

将获取到的token放到Name接口的Header里,再次调用成功!!!

Envoy实现.NET架构的网关(四)集成IdentityServer4实现OAuth2认证

 

至此,我们通过Envoy+IdentityServer4实现了网关的JWT认证,可以节省内部微服务与IdentityServer4重复的集成工作,实现了统一处理认证逻辑。