上一篇介绍了在不整合Consul的情况下,如何使用identity server。在实际应用环境中,内部服务一般是不对外暴露的,所以现在我们把consul考虑进来,稍作修改就可以了。

环境介绍,我们有一个OrderService和PartnerService,其中的/api/default是受权限保护的,还有一个ocelot网关和identity server4的权限服务。

可以参照之前的文章先把权限服务集成到consul。

大致流程是:首先在网关注册认证服务,修改认证服务资源,在api服务中集成认证

API网关注册认证服务

修改Startup

// IdentityServer
            #region IdentityServerAuthenticationOptions => need to refactor
            Action<IdentityServerAuthenticationOptions> isaOptClient = option =>
            {
                option.Authority = Configuration["IdentityService:Uri"];
                option.ApiName = "serviceorder";
                option.RequireHttpsMetadata = Convert.ToBoolean(Configuration["IdentityService:UseHttps"]);
                option.SupportedTokens = SupportedTokens.Both;
                option.ApiSecret = Configuration["IdentityService:ApiSecrets:orderservice"];
            };

            Action<IdentityServerAuthenticationOptions> isaOptProduct = option =>
            {
                option.Authority = Configuration["IdentityService:Uri"];
                option.ApiName = "servicepartner";
                option.RequireHttpsMetadata = Convert.ToBoolean(Configuration["IdentityService:UseHttps"]);
                option.SupportedTokens = SupportedTokens.Both;
                option.ApiSecret = Configuration["IdentityService:ApiSecrets:partnerservice"];
            };
            #endregion

            services.AddAuthentication()
                .AddIdentityServerAuthentication("PartnerServiceKey", isaOptProduct)
                .AddIdentityServerAuthentication("OrderServiceKey", isaOptClient);

配置文件如下

{
  "Swagger": {
    "DocName": "ZJ.ApiGateway",
    "Version": "v1",
    "Title": "API Gateway Service",
    "ServiceDocNames": "serviceorder,servicepartner,serviceauthorize" // Swagger doc name list
  },
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "IdentityService": {
    "Uri": "http://192.168.8.157:5100",
    "UseHttps": false,
    "ApiSecrets": {
      "orderservice": "ordersecret",
      "partnerservice": "partnersecret"
    }
  },
  "AllowedHosts": "*"
}

 修改ocelotsettings.json,给权限服务加上路由,如果需要swagger,也加上

// API:Service.Authorize
    // --> swagger part
    {
      "DownstreamPathTemplate": "/doc/serviceauthorize-gateway/swagger.json",
      "DownstreamScheme": "http",
      "ServiceName": "Service.Authorize",
      "LoadBalancer": "RoundRobin",
      "UseServiceDiscovery": true,
      "UpstreamPathTemplate": "/doc/serviceauthorize/swagger.json",
      "UpstreamHttpMethod": [ "GET", "POST", "DELETE", "PUT" ]
    },
    {
      "UseServiceDiscovery": true, // use Consul service discovery
      "DownstreamPathTemplate": "/{url}",
      "DownstreamScheme": "http",
      "ServiceName": "Service.Authorize",
      "LoadBalancerOptions": {
        "Type": "RoundRobin"
      },
      "UpstreamPathTemplate": "/api/Serviceauthorize/{url}",
      "UpstreamHttpMethod": [ "Get", "Post" ],
      "ReRoutesCaseSensitive": false, // non case sensitive
      "QoSOptions": {
        "ExceptionsAllowedBeforeBreaking": 2, // 允许多少个异常请求
        "DurationOfBreak": 5000, // 熔断的时间,单位为毫秒
        "TimeoutValue": 3000 // 如果下游请求的处理时间超过多少则视如该请求超时
      }
    }

 

修改权限服务

修改IdentityServerConfig类

public static class IdentityServerConfig
    {
        /// <summary>
        /// 允许使用认证服务的api列表
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<ApiResource> GetApiResources()
        {
            return new List<ApiResource>
            {
                new ApiResource("serviceorder", "Default (all) API"),
                new ApiResource("servicepartner", "Default (all) API1"),
            };
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<IdentityResource> GetIdentityResources()
        {
            return new List<IdentityResource>
            {
                new IdentityResources.OpenId(),
                new IdentityResources.Profile(),
                new IdentityResources.Email(),
                new IdentityResources.Phone()
            };
        }

        /// <summary>
        /// 允许使用认证服务的应用客户端
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<Client> GetClients(IConfiguration Configuration)
        {
            return new List<Client>
            {
                new Client
                {
                    ClientId = "default_web_client",
                    ClientName="default_name",
                    AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
                    AllowedScopes =
                    {
                        "serviceorder",
                        "servicepartner",
                    },
                    ClientSecrets = new[]{ new Secret("secret1".Sha256())}
                },
                new Client
                {
                    ClientId = "default_app_client",
                    ClientName="default_name11",
                    AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
                    AllowedScopes =
                    {
                        "serviceorder",
                    },
                    ClientSecrets = new[]{ new Secret("secret2".Sha256())}
                },
                new Client
                {
                    ClientId = "default_mvc_client",
                    ClientName="default_name111",
                    AllowedGrantTypes = GrantTypes.Implicit,
                    RedirectUris = { Configuration["Clients:MvcClient:RedirectUri"] },
                    AllowedScopes =
                    {
                        "serviceorder",
                    },
                    ClientSecrets = new[]{ new Secret("secret3".Sha256())}
                }
            };
        }

    }

注意这里的Clients,这么设定的目的是当使用default_web_client时可以访问servicePartner以及serviceOrder,当使用default_app_client时只能访问serviceorder

 

修改api服务

修改ConfigureServices

// identity server
            services.AddMvcCore().AddAuthorization().AddJsonFormatters();
            services.AddAuthentication(_appConfiguration["IdentityService:DefaultScheme"]).AddIdentityServerAuthentication(_appConfiguration["IdentityService:DefaultScheme"], options =>
            {
                options.Authority = _appConfiguration["IdentityService:Uri"];
                options.RequireHttpsMetadata = false;
                options.ApiName = "serviceorder"; // match with configuration in IdentityServer
            });

配置文件如下,注意defaultScheme必须和网关中配置的AddIdentityServerAuthentication一致

"IdentityService": {
    "Uri": "http://192.168.8.157:5100",
    "DefaultScheme": "OrderServiceKey",
    "UseHttps": false,
    "ApiSecret": "clientsecret"
  }

发布到iis开始测试,我的测试环境中order服务端口是5000,partner服务端口是5001,认证服务端口5100,api网关端口5555

首先请求token,地址填写api网关地址,client_id、client_secret和权限服务中设置的一致,其他按下图填写

samba集成AD_API

 

 成功请求到token,按照我们在权限服务中的配置,这个token是属于default_web_client的,那么它可以用在serviceorder和servicepartner这两个api中

samba集成AD_List_02

请求serviceorder,可以正常获得结果,注意在Auth选项卡中选择Bearer Token并填写刚才取得的access_token

samba集成AD_json_03

请求servicepartner,也可以正常返回结果

samba集成AD_samba集成AD_04

现在我们换一个clientId,换成default_app_client,理论上它只能请求serviceorder,而不能请求servicepartner

samba集成AD_json_05

samba集成AD_samba集成AD_06

samba集成AD_List_07

可以看到请求servicepartner时返回了401 Unauthorized,测试通过。

隐藏client_secret

 上述方式有一个较大的问题,那就是client_id对应的client_secret会暴露在客户端的请求体中。既然验证请求要经过api网关,那可以考虑在api网关做一次人工转发,在请求体中加上这个client_secret,具体可以看参考文章,此处不再展开。

总结

到这一步,微服务架构已经基本成型,consul作为服务中心统筹管理所有的api服务,独立的权限服务通过consul提供权限验证、用户注册、注销等功能。下一步需要重构代码,重新梳理项目结构,整理完成后接入CAP就基本可以开始开发。