上一篇介绍了在不整合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和权限服务中设置的一致,其他按下图填写
成功请求到token,按照我们在权限服务中的配置,这个token是属于default_web_client的,那么它可以用在serviceorder和servicepartner这两个api中
请求serviceorder,可以正常获得结果,注意在Auth选项卡中选择Bearer Token并填写刚才取得的access_token
请求servicepartner,也可以正常返回结果
现在我们换一个clientId,换成default_app_client,理论上它只能请求serviceorder,而不能请求servicepartner
可以看到请求servicepartner时返回了401 Unauthorized,测试通过。
隐藏client_secret
上述方式有一个较大的问题,那就是client_id对应的client_secret会暴露在客户端的请求体中。既然验证请求要经过api网关,那可以考虑在api网关做一次人工转发,在请求体中加上这个client_secret,具体可以看参考文章,此处不再展开。
总结
到这一步,微服务架构已经基本成型,consul作为服务中心统筹管理所有的api服务,独立的权限服务通过consul提供权限验证、用户注册、注销等功能。下一步需要重构代码,重新梳理项目结构,整理完成后接入CAP就基本可以开始开发。
参考文章: