上一篇介紹了在不整合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就基本可以開始開發。
參考文章:
