前一篇文章《.NET Core 微服務—API網關(Ocelot) 教程 [二]》已經讓Ocelot和目錄api(Api.Catalog)、訂單api(Api.Ordering)經過網關方式運行起來了。但在平常開發中Api並非全部人都能訪問的,是添加了認證、受權的。那麼本篇文章就將繼續介紹Ocelot如何和 IdentityServer4 認證服務如何配合使用的。html
建立認證服務(Api.IdentityServer)git
一、建立一個空的WebApi項目-Api.IdentityServer,並添加IdentityServer4項目引用:以下圖:github
Install-Package IdentityServer4
二、要啓用IdentityServer服務,不只要把 IdentityServer 註冊到容器中, 還須要配置一下內容:數據庫
哪些客戶端 Client(應用) 可使用這個 Authorization Server;json
指定可使用 Authorization Server 受權的 Users(用戶)api
a) 建立文件 InMemoryConfig.cs,用於設置以上相關內容:app
1 using IdentityServer4; 2 using IdentityServer4.Models; 3 using IdentityServer4.Test; 4 using System; 5 using System.Collections.Generic; 6 using System.Linq; 7 using System.Threading.Tasks; 8 9 namespace Api.IdentityServer 10 { 11 public class InMemoryConfig 12 { 13 public static IEnumerable<IdentityResource> GetIdentityResourceResources() 14 { 15 return new List<IdentityResource> 16 { 17 //必需要添加,不然報無效的scope錯誤 18 new IdentityResources.OpenId(), 19 }; 20 } 21 22 /// <summary> 23 /// api資源列表 24 /// </summary> 25 /// <returns></returns> 26 public static IEnumerable<ApiResource> GetApiResources() 27 { 28 //可訪問的API資源(資源名,資源描述) 29 return new List<ApiResource> 30 { 31 new ApiResource("Api.Catalog", "Api.Catalog"), 32 new ApiResource("Api.Ordering", "Api.Ordering") 33 }; 34 } 35 36 /// <summary> 37 /// 客戶端列表 38 /// </summary> 39 /// <returns></returns> 40 public static IEnumerable<Client> GetClients() 41 { 42 return new List<Client> 43 { 44 new Client 45 { 46 ClientId = "client_Catalog", //訪問客戶端Id,必須惟一 47 //使用客戶端受權模式,客戶端只須要clientid和secrets就能夠訪問對應的api資源。 48 AllowedGrantTypes = GrantTypes.ClientCredentials, 49 ClientSecrets = 50 { 51 new Secret("secret".Sha256()) 52 }, 53 AllowedScopes = { "Api.Catalog", IdentityServerConstants.StandardScopes.OpenId,IdentityServerConstants.StandardScopes.Profile } 54 }, 55 new Client 56 { 57 ClientId = "client_Ordering", 58 ClientSecrets = new [] { new Secret("secret".Sha256()) }, 59 //這裏使用的是經過用戶名密碼和ClientCredentials來換取token的方式. ClientCredentials容許Client只使用ClientSecrets來獲取token. 這比較適合那種沒有用戶參與的api動做 60 AllowedGrantTypes = GrantTypes.ResourceOwnerPasswordAndClientCredentials, 61 AllowedScopes = { "Api.Ordering", IdentityServerConstants.StandardScopes.OpenId,IdentityServerConstants.StandardScopes.Profile } 62 } 63 }; 64 } 65 66 /// <summary> 67 /// 指定可使用 Authorization Server 受權的 Users(用戶) 68 /// </summary> 69 /// <returns></returns> 70 public static IEnumerable<TestUser> Users() 71 { 72 return new[] 73 { 74 new TestUser 75 { 76 SubjectId = "1", 77 Username = "cba", 78 Password = "abc" 79 } 80 }; 81 } 82 } 83 }
GetApiResources:這裏指定了name和display name, 之後api使用authorization server的時候, 這個name必定要一致asp.net
GetClients: 認證客戶端列表ide
Users: 這裏的內存用戶的類型是TestUser, 只適合學習和測試使用, 實際生產環境中仍是須要使用數據庫來存儲用戶信息的, 例如接下來會使用asp.net core identity. TestUser的SubjectId是惟一標識.微服務
b) 在Startup.cs中啓用IdentityServer服務
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Threading.Tasks; 5 using Microsoft.AspNetCore.Builder; 6 using Microsoft.AspNetCore.Hosting; 7 using Microsoft.AspNetCore.Mvc; 8 using Microsoft.Extensions.Configuration; 9 using Microsoft.Extensions.DependencyInjection; 10 using Microsoft.Extensions.Hosting; 11 using Microsoft.Extensions.Logging; 12 13 namespace Api.IdentityServer 14 { 15 public class Startup 16 { 17 public Startup(IConfiguration configuration) 18 { 19 Configuration = configuration; 20 } 21 22 public IConfiguration Configuration { get; } 23 24 // This method gets called by the runtime. Use this method to add services to the container. 25 public void ConfigureServices(IServiceCollection services) 26 { 27 services.AddControllers(); 28 29 services.AddIdentityServer() 30 .AddDeveloperSigningCredential() 31 .AddInMemoryApiResources(InMemoryConfig.GetApiResources()) 32 .AddInMemoryClients(InMemoryConfig.GetClients()) 33 .AddTestUsers(InMemoryConfig.Users().ToList()); 34 35 services.AddAuthentication();//配置認證服務 36 } 37 38 // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 39 public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 40 { 41 if (env.IsDevelopment()) 42 { 43 app.UseDeveloperExceptionPage(); 44 } 45 app.UseStaticFiles(); 46 app.UseRouting(); 47 48 app.UseIdentityServer(); 49 50 app.UseAuthentication(); 51 app.UseAuthorization(); 52 53 app.UseEndpoints(endpoints => 54 { 55 endpoints.MapControllers(); 56 }); 57 } 58 } 59 }
一、添加IdentityServer4.AccessTokenValidation的包,也能夠經過程序包管理控制檯執行如下命令
Install-Package IdentityServer4.AccessTokenValidation
添加包引用後,在Startup中的 ConfigureServices
中分別註冊兩個認證方案 Configure
中配置IdentityServer服務。
public void ConfigureServices(IServiceCollection services) { services.AddAuthentication() .AddJwtBearer("Api.Catalog", i => { i.Audience = "Api.Catalog"; i.Authority = "http://localhost:5332"; i.RequireHttpsMetadata = false; }).AddJwtBearer("Api.Ordering", y => { y.Audience = "Api.Ordering"; y.Authority = "http://localhost:5331"; y.RequireHttpsMetadata = false; }); services.AddOcelot();//注入Ocelot服務 services.AddControllers(); }
二、修改ocelot配置文件,在Routes中添加受權信息
調整ApiGateway.Ocelot項目中ocelot.json配置文件以下:
{ "GlobalConfiguration": { }, "Routes": [ { "DownstreamPathTemplate": "/api/{controller}/{action}", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5331 } ], "UpstreamPathTemplate": "/Catalog/{controller}/{action}", "UpstreamHttpMethod": [ "Get", "Post" ], "LoadBalancerOptions": { "Type": "RoundRobin" }, //受權信息 "AuthenticationOptions": { "AuthenticationProviderKey": "Api.Catalog", "AllowedScopes": [] } }, { "DownstreamPathTemplate": "/api/{controller}/{action}", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5332 } ], "UpstreamPathTemplate": "/Ordering/{controller}/{action}", "UpstreamHttpMethod": [ "Get", "Post" ], "LoadBalancerOptions": { "Type": "RoundRobin" }, //受權信息 "AuthenticationOptions": { "AuthenticationProviderKey": "Api.Ordering", "AllowedScopes": [] } } ] }
Ocelot會去檢查Routes是否配置了AuthenticationOptions節點。若是有會根據配置的認證方案進行身份認證。若是沒有則不進行身份認證。
AuthenticationProviderKey 是剛纔註冊的認證方案。
AllowedScopes 是 AllowedScopes中配置的受權訪問範圍。
一、根據網關設置訪問:目錄api:http://localhost:5330/Ordering/Values/1
如圖:
二、先獲取Token後再訪問該接口:
根據獲取Token在http://localhost:5330/Ordering/Values/1 請求時,添加認證頭信息,便可請求成功
一、在IdentityServer註冊相關資源服務和客戶端信息。
二、Ocelot經過註冊認證方案,在配置文件中指定路由的認證方案
三、該認證是在Ocelot網關層對相關資源進行認證,並不是資源服務認證
四、認證調用失敗時,嘗試把IdentityServer包版本下降嘗試
源碼:https://github.com/cwsheng/ocelot.Demo.git