前言:
前一篇文章《.NET Core 微服務—API網關(Ocelot) 教程 [二]》已經讓Ocelot和目錄api(Api.Catalog)、訂單api(Api.Ordering)通過網關方式運行起來了。但在日常開發中Api並不是所有人都能訪問的,是添加了認證、授權的。那么本篇文章就將繼續介紹Ocelot如何和 IdentityServer4 認證服務如何配合使用的。
創建認證服務(Api.IdentityServer)
1、創建一個空的WebApi項目-Api.IdentityServer,並添加IdentityServer4項目引用:如下圖:
Install-Package IdentityServer4
2、要啟用IdentityServer服務,不僅要把 IdentityServer 注冊到容器中, 還需要配置一下內容:
- Authorization Server 保護了哪些 API (資源);
-
哪些客戶端 Client(應用) 可以使用這個 Authorization Server;
-
指定可以使用 Authorization Server 授權的 Users(用戶)
a) 創建文件 InMemoryConfig.cs,用於設置以上相關內容:

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一定要一致
GetClients: 認證客戶端列表
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 }
為ocelot項目集成IdentityServer
1、添加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(); }
2、修改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中配置的授權訪問范圍。
驗證效果
1、根據網關設置訪問:目錄api:http://localhost:5330/Ordering/Values/1
如圖:
2、先獲取Token后再訪問該接口:
根據獲取Token在http://localhost:5330/Ordering/Values/1 請求時,添加認證頭信息,即可請求成功
回顧總結
1、在IdentityServer注冊相關資源服務和客戶端信息。
2、Ocelot通過注冊認證方案,在配置文件中指定路由的認證方案
3、該認證是在Ocelot網關層對相關資源進行認證,並非資源服務認證
4、認證調用失敗時,嘗試把IdentityServer包版本降低嘗試
源碼:https://github.com/cwsheng/ocelot.Demo.git