Angular SPA基于Ocelot API网关与IdentityServer4的身份认证与授权(二)
上文已經(jīng)介紹了Identity Service的實(shí)現(xiàn)過程。今天我們繼續(xù),實(shí)現(xiàn)一個(gè)簡(jiǎn)單的Weather API和一個(gè)基于Ocelot的API網(wǎng)關(guān)。
回顧
《Angular SPA基于Ocelot API網(wǎng)關(guān)與IdentityServer4的身份認(rèn)證與授權(quán)(一)》
Weather API
Weather API實(shí)現(xiàn)非常簡(jiǎn)單,直接用Visual Studio 2019 Community Edition自帶的ASP.NET Core Web Application模板創(chuàng)建就行了,我們的目的不是為了實(shí)現(xiàn)Weather API的業(yè)務(wù),我們只需要有一個(gè)能讓IdentityServer4進(jìn)行保護(hù)的API就行,以便能夠完成我們的各種實(shí)驗(yàn)。
在原有的(也就是Identity Service所在的)解決方案中,新建一個(gè)ASP.NET Core Web Application,應(yīng)用程序模板選擇API,并禁用HTTPS和Docker支持,因?yàn)槟壳安恍枰?#xff0c;也不要啟用任何Authentication機(jī)制,因?yàn)檫@部分功能會(huì)由Ocelot配合IdentityServer4實(shí)現(xiàn)。在完成創(chuàng)建之后,我們的Weather API就做好了。
現(xiàn)在,設(shè)置啟動(dòng)端口為5000,啟動(dòng)項(xiàng)目,然后通過curl測(cè)試API是否工作正常:
1 | curl http://localhost:5000/weatherforecast | json_pp && echo |
OK,Weather API就成功完成了。
Ocelot API網(wǎng)關(guān)
現(xiàn)在我們來創(chuàng)建Ocelot API網(wǎng)關(guān),首先做到能夠通過這個(gè)網(wǎng)關(guān)來訪問Weather API,然后再加入認(rèn)證機(jī)制,使得Ocelot API網(wǎng)關(guān)能夠基于IdentityServer4完成認(rèn)證。其實(shí)這部分實(shí)操我已經(jīng)在《ASP.NET Core中Ocelot的使用:API網(wǎng)關(guān)的應(yīng)用》和《使用Ocelot、IdentityServer4、Spring Cloud Eureka搭建微服務(wù)網(wǎng)關(guān):Step by Step(二)》這些文章中介紹過了。為了保證描述的完整性,我還是把這部分工作重新做一次。
搭建網(wǎng)關(guān)
新建一個(gè)ASP.NET Core Web Application應(yīng)用程序,模板選擇Empty,去掉HTTPS支持。在項(xiàng)目創(chuàng)建后,向項(xiàng)目添加ocelot.config.json文件,內(nèi)容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | { ??"ReRoutes": [ ????{ ??????"DownstreamPathTemplate": "/weatherforecast", ??????"DownstreamScheme": "http", ??????"DownstreamHostAndPorts": [ ????????{ ??????????"Host": "localhost", ??????????"Port": 5000 ????????} ??????], ??????"UpstreamPathTemplate": "/api/weather", ??????"UpstreamHttpMethod": [ "Get" ] ????} ??] } |
然后,向項(xiàng)目添加Ocelot的NuGet包,修改Program.cs文件,將ocelot.config.json文件添加到應(yīng)用程序配置系統(tǒng)中:
1 2 3 4 5 6 7 8 9 10 | public static IHostBuilder CreateHostBuilder(string[] args) => ????Host.CreateDefaultBuilder(args) ????????.ConfigureWebHostDefaults(webBuilder => ????????{ ????????????webBuilder.UseStartup<Startup>(); ????????}) ????????.ConfigureAppConfiguration(configBuilder => ????????{ ????????????configBuilder.AddJsonFile("ocelot.configuration.json"); ????????}); |
并且修改Startup.cs文件,加入Ocelot的服務(wù)注冊(cè)以及Middleware:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public void ConfigureServices(IServiceCollection services) { ????services.AddOcelot(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { ????if (env.IsDevelopment()) ????{ ????????app.UseDeveloperExceptionPage(); ????} ? ????app.UseRouting(); ????app.UseOcelot(); ? ????app.UseEndpoints(endpoints => ????{ ????????endpoints.MapGet("/", async context => ????????{ ????????????await context.Response.WriteAsync("Hello World!"); ????????}); ????}); } |
讓API網(wǎng)關(guān)偵聽9000端口,同時(shí)啟動(dòng)Weather API和API網(wǎng)關(guān)兩個(gè)項(xiàng)目,于是我們可以直接通過API網(wǎng)關(guān)來訪問Weather API:
1 | curl http://localhost:9000/api/weather | json_pp && echo |
可以看到,我們已經(jīng)可以直接通過API網(wǎng)關(guān)的地址來訪問其下游服務(wù)了。
在網(wǎng)關(guān)上實(shí)現(xiàn)身份認(rèn)證
接下來的這一步,我們會(huì)結(jié)合前一篇文章中介紹的Identity Service,在API網(wǎng)關(guān)上實(shí)現(xiàn)身份認(rèn)證。在Ocelot API網(wǎng)關(guān)項(xiàng)目上,添加IdentityServer4.AccessTokenValidation NuGet包的引用,然后在Startup.cs的ConfigureServices中增加對(duì)IdentityServer4的認(rèn)證支持:
1 2 3 4 5 6 7 8 9 10 11 12 13 | public void ConfigureServices(IServiceCollection services) { ????services.AddOcelot(); ????services.AddAuthentication() ????????.AddIdentityServerAuthentication("AuthKey", options => ????????{ ????????????options.Authority = "http://localhost:7889"; ????????????options.RequireHttpsMetadata = false; ????????}); ????services.AddCors(options => options.AddPolicy("AllowAll", p => p.AllowAnyOrigin() ???????.AllowAnyMethod() ???????.AllowAnyHeader())); } |
當(dāng)然我們也添加了CORS的Policy,以便能夠支持跨域訪問,為之后的Angular SPA實(shí)現(xiàn)做準(zhǔn)備。目前,無需對(duì)Configure方法做大的改動(dòng),只需要添加app.UseCors(“AllowAll”);這一調(diào)用,以允許跨域訪問即可。然后,修改ocelot.config.json文件,在Weather API的ReRoute上增加AuthenticationOptions配置,用以啟用基于IdentityServer4的身份認(rèn)證:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | { ??"ReRoutes": [ ????{ ??????"DownstreamPathTemplate": "/weatherforecast", ??????"DownstreamScheme": "http", ??????"DownstreamHostAndPorts": [ ????????{ ??????????"Host": "localhost", ??????????"Port": 5000 ????????} ??????], ??????"UpstreamPathTemplate": "/api/weather", ??????"UpstreamHttpMethod": [ "Get" ], ??????"AuthenticationOptions": { ????????"AuthenticationProviderKey": "AuthKey", ????????"AllowedScopes": [] ??????} ????} ??] } |
現(xiàn)在,同時(shí)啟動(dòng)Identity Service、Weather API和Ocelot網(wǎng)關(guān)三個(gè)項(xiàng)目,然后再用curl調(diào)用上面相同的地址,可以發(fā)現(xiàn),服務(wù)端已經(jīng)返回了401,告訴我們沒有認(rèn)證,無法發(fā)起API調(diào)用請(qǐng)求:
進(jìn)一步測(cè)試
現(xiàn)在,讓我們寫一個(gè)Console App作為客戶端,進(jìn)行進(jìn)一步測(cè)試。新建一個(gè).NET Core Console App的項(xiàng)目,添加IdentityModel NuGet包,Main方法實(shí)現(xiàn)如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | static async Task Main(string[] args) { ????using var client = new HttpClient(); ????var discoResponse = await client.GetDiscoveryDocumentAsync("https://localhost:7890"); ????if (discoResponse.IsError) ????{ ????????Console.WriteLine(discoResponse.Error); ????????return; ????} ? ????var tokenResponse = await client.RequestPasswordTokenAsync(new PasswordTokenRequest ????{ ????????Address = discoResponse.TokenEndpoint, ????????ClientId = "webapi", ????????Scope = "api.weather.full_access", ????????ClientSecret = "mysecret", ????????UserName = "daxnet", ????????Password = "P@ssw0rd123" ????}); ? ????if (tokenResponse.IsError) ????{ ????????Console.WriteLine(tokenResponse.Error); ????????return; ????} ? ????Console.WriteLine(tokenResponse.Json); ????client.SetBearerToken(tokenResponse.AccessToken); ????var response = await client.GetAsync("http://localhost:9000/api/weather"); ????Console.WriteLine(response.IsSuccessStatusCode ? ????????$"{response.StatusCode} {await response.Content.ReadAsStringAsync()}" : ????????response.StatusCode.ToString()); } |
仍然同時(shí)啟動(dòng)Identity Service、Weather API和Ocelot網(wǎng)關(guān)三個(gè)項(xiàng)目,然后調(diào)試這個(gè)Console App,可以看到,API調(diào)用成功:
Console App也返回了正確的結(jié)果:
然后,將上面的access_token復(fù)制下來,打開https://jwt.io,粘貼到Encoded文本框,在Decoded文本框中可以看到,Identity相關(guān)的信息,包括我們?cè)贏piResource上設(shè)定的Claims都被包含在了Access Token上:
?
小結(jié)
本文實(shí)現(xiàn)了一個(gè)實(shí)驗(yàn)性質(zhì)的Weather API,然后搭建了一個(gè)Ocelot API網(wǎng)關(guān),并在網(wǎng)關(guān)上結(jié)合Identity Service完成了身份認(rèn)證機(jī)制,最后通過一個(gè)Console App,了解了一下Access Token。下文開始,我會(huì)介紹如何在Angular SPA中做身份認(rèn)證。
源代碼
訪問以下Github地址以獲取源代碼:
https://github.com/daxnet/identity-demo
總結(jié)
以上是生活随笔為你收集整理的Angular SPA基于Ocelot API网关与IdentityServer4的身份认证与授权(二)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【翻译】.NET 5 Preview 1
- 下一篇: DotNetCore Web应用程序中的