AspNetCore網關集成Swagger訪問使用IdentityServer保護的webapi項目

来源:https://www.cnblogs.com/fallTakeMan/archive/2019/08/08/11289713.html
-Advertisement-
Play Games

創建webapi項目 創建四個webapi項目,兩個處理業務,一個網關,一個驗證中心。四個項目對應的埠如下, ApiGateway:1999 IdentityServer:16690 Services.Api1:2108 Services.Api2:2343 添加Swagger支持 在兩個業務項目 ...


創建webapi項目

  創建四個webapi項目,兩個處理業務,一個網關,一個驗證中心。四個項目對應的埠如下,

ApiGateway:1999

IdentityServer:16690

Services.Api1:2108

Services.Api2:2343

 

添加Swagger支持

  在兩個業務項目中分別引用Swashbuckle.AspNetCore,目前是最新版本是4.0.1。在項目屬性面板,設置輸出xml文檔,swagger可以讀取xml註釋生成json文件,在swagger ui頁面中顯示。但是選擇輸出xml文檔後,對於沒有xml註釋的類和方法會顯示警告,可以在項目屬性面板中【錯誤和警告】選項,取消顯示警告中添加1591,這樣就可以不顯示缺少xml註釋的警告了。對於強迫症的你暫時可以平復一下了,當然,真的強迫症的話,肯定會全部加上xml註釋的。(¬_¬)瞄

   Startup.ConfigureServices

public void ConfigureServices(IServiceCollection services)
        {
           services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

            services.AddSwaggerGen(options =>
            {
                //SwaggerDoc的第一個參數要與Configure中SwaggerEndPoint中的版本名稱一致
                //既可以使用版本號,也可以使用自定義名稱
                options.SwaggerDoc("ServiceApiTwo", new Info
                {
                    Title = "Services.Api #two",
                    Version = "v1",
                    Description = "服務api #two",
                    License = new License
                    {
                        Name = "APL2.0",
                        Url = "https://opensource.org/licenses/Apache-2.0"
                    },
                    Contact = new Contact
                    {
                        Name = "原來是李",
                        Url = "https://www.cnblogs.com/falltakeman"
                    }
                });
                var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
                var xmlPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, xmlFile);
                options.IncludeXmlComments(xmlPath);
                
            });
        }

  Startup.Configure

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();

                app.UseSwagger(c=>
                {
                    c.RouteTemplate = "{documentName}/swagger.json";
                });
                app.UseSwaggerUI(u =>
                {
                    u.SwaggerEndpoint("/ServiceApiTwo/swagger.json", "ServiceApiTwo");
                    u.DocumentTitle = "Service Api #2 文檔";
                });
            }
            
            app.UseMvc();
        }

   配置好啟動項目看看。

  通過swagger發起請求,響應正常。

 

 

配置網關項目

  使用目前比較流行的開源網關服務Ocelot,APIGateway項目添加引用Ocelot、Ocelot.Provider.Consul、Ocelot.Provider.Polly、Ocelot.Cache.CacheManager,目前用到的版本是13.5.2。要在網關中統一查看各個服務的swagger文檔,還需引用Swash.AspNetCore。Consul的配置先不說了。

  在項目根路徑下添加OcelotConfig.json配置文件。處理正常的路由轉發外,要在網關swagger頁面訪問業務api,還需要配置swagger路由轉發。

{
  "GlobalConfiguration": {
    //外部訪問路徑
    "BaseUrl": "http://localhost:1999",
    //限速配置
    "RateLimitOptions": {
      //白名單
      "ClientWhitelist": [],
      "EnableRateLimiting": true,
      //限制時間段,例如1s,5m,1h,1d
      "Period": "1s",
      //等待重試等待的時間間隔(秒)
      "PeriodTimespan": 1,
      //限制
      "Limit": 1,
      //自定義消息
      "QuotaExceededMessage": "單位時間內請求次數超過限制。",
      "HttpStatusCode": 999
    },
    //服務發現配置
    "ServiceDiscoveryProvider": {
      "Host": "localhost",
      "Port": 8500,
      "Type": "PollConsul",
      "PollingInterval": 1000
    },
    //熔斷配置
    "QoSOptions": {
      "ExceptionsAllowedBeforeBreaking": 3,
      "DurationOfBreak": 5,
      //超時值(毫秒)
      "TimeoutValue": 5000
    }
  },
  "ReRoutes": [
    // Api#one項目配置
    {
      "UpstreamPathTemplate": "/gateway/one/{url}", //上游路徑模板
      "UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete" ], //上游HTTP請求方法
      "DownstreamPathTemplate": "/api/{url}", //下游路徑模板
      "DownstreamScheme": "http", //下游協議 https/http
      "ServiceName": "ServiceApiOne", //服務名稱(結合服務發現使用)
      "UseServiceDiscovery": true, //啟用服務發現
      "LoadBalancer": "RoundRobin", //負載均衡演算法:RoundRobin-輪詢;LeastConnection-最少連接數(最空閑的伺服器);NoLoadBalancer-總是發送往第一個請求或者服務發現
      //下游主機與埠,允許配置多個
      "DownstreamHostAndPorts": [
        //{
        //  "Host": "ip",
        //  "Port": 80
        //},
        {
          "Host": "localhost",
          "Port": 2108
        }
      ],
      //熔斷配置,在請求下游服務時使用斷路
      "QoSOptions": {
        "ExceptionsAllowedBeforeBreaking": 3,
        "DurationOfBreak": 10,
        "TimeoutValue": 5000
      },
      //許可權配置
      //"AuthenticationOptions": {
      //  "AuthenticationProviderKey": "Bearer",
      //  "AllowedScopes": []
      //}
    },
    // Api#two項目配置
    {
      "UpstreamPathTemplate": "/gateway/two/{url}",
      "UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete" ],
      "DownstreamPathTemplate": "/api/{url}",
      "DownstreamScheme": "http",
      "ServiceName": "ServiceApiTwo",
      "UseServiceDiscovery": true,
      "LoadBalancer": "RoundRobin",
      "DownstreamHostAndPorts": [
        //{
        //  "Host": "ip",
        //  "Port": 80
        //},
        {
          "Host": "localhost",
          "Port": 2343
        }
      ],
      "QoSOptions": {
        "ExceptionsAllowedBeforeBreaking": 3,
        "DurationOfBreak": 10,
        "TimeoutValue": 5000
      },
      //"AuthenticationOptions": {
      //  "AuthenticationProviderKey": "Bearer",
      //  "AllowedScopes": []
      //}
    },
    //swagger api2配置
    {
      "UpstreamPathTemplate": "/ServiceApiTwo/swagger.json",
      "UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete" ],
      "DownstreamPathTemplate": "/ServiceApiTwo/swagger.json",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 2343
        }
      ]
    },
    //swagger api1多版本配置v1.0
    {
      "UpstreamPathTemplate": "/ServiceApiOne/1.0/swagger.json",
      "UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete" ],
      "DownstreamPathTemplate": "/ServiceApiOne/1.0/swagger.json",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 2108
        }
      ]
    },
    //swagger api1多版本配置v2.0
    {
      "UpstreamPathTemplate": "/ServiceApiOne/2.0/swagger.json",
      "UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete" ],
      "DownstreamPathTemplate": "/ServiceApiOne/2.0/swagger.json",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 2108
        }
      ]
    }
  ]
}

 

  Startup.ConfigureServices註冊swagger和Ocelot網關服務,ConfigureServices中的swagger配置和業務api中一樣,

services.AddOcelot(Configuration)
                .AddConsul()
                .AddCacheManager(c => c.WithDictionaryHandle())
                .AddPolly();

services.AddSwaggerGen(options =>
            {
                options.SwaggerDoc(Configuration["Swagger:Name"], new Info
                {
                    Title = Configuration["Swagger:Title"],
                    Version = Configuration["Swagger:Version"],
                    Description = Configuration["Swagger:Description"],
                    License = new License
                    {
                        Name = Configuration["Swagger:License:Name"],
                        Url = Configuration["Swagger:License:Url"]
                    },
                    Contact = new Contact
                    {
                        Name = Configuration["Swagger:Contact:Name"],
                        Email = Configuration["Swagger:Contact:Email"],
                        Url = Configuration["Swagger:Contact:Url"]
                    }
                });
            });

  Startup.Configure中,我是使用了配置文件,將業務api的swagger節點寫在了配置文件中。

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                // 配置文件中的SwaggerName為業務api中是SwaggerEndPoint名稱,有版本號的帶上版本號
                var apis = Configuration["SwaggerApis:SwaggerName"].Split(';').ToList();
                app.UseSwagger();
                app.UseSwaggerUI(options=>
                {
                    //顯示註冊到網關的api介面
                    apis.ForEach(key =>
                    {
                        options.SwaggerEndpoint($"/{key}/swagger.json", key);
                    });
                    options.DocumentTitle = "api網關";
                });

            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseStaticFiles();
            app.UseCookiePolicy();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });

            app.UseOcelot().Wait(); // 使用Ocelot網關中間件

        }

  修改ApiGateway項目Program.cs將配置文件添加進來。

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext,config)=>
            {
                var env = hostingContext.HostingEnvironment;
                //根據環境變數載入不同的json配置
                config.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
                .AddJsonFile("OcelotConfig.json")//網關配置
                .AddEnvironmentVariables();//環境變數
            })
            .ConfigureLogging((hostingContext,logging)=>
            {
                logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
                
                logging.AddConsole();
                //添加調試日誌
                logging.AddDebug();
            })
            .UseStartup<Startup>();

  網關配置了,swagger也配置了,啟動業務api和網關服務看看效果。

   兩個業務api的swagger文檔都可以正常查看。發請求看一下,結果響應404,仔細看一下,請求的服務地址是網關服務的地址,而不是業務api的地址,難道是Ocelot網關路由配置錯了?使用Postman發一個GET請求看看,localhost:1999/gateway/two/values,網關轉發到localhost:2343/api/values,響應正常。

   看swashbuckle文檔這一段,將業務api中Configure加上這一段後再次通過網關發起請求,結果出現TypeError。既然出錯了,打開瀏覽器調試工具看一下就明白了,Failed to load http://localhost:2343/api/ApiTwo: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:1999' is therefore not allowed access.

  網關請求業務api跨域了,要讓業務api允許來自網關的請求,需要設置業務api跨域請求政策。加上下麵的配置後,網關請求正常了。

  修改Startup.Configure

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();

                app.UseSwagger(c=>
                {
                    //處理網關通過swagger訪問
                    c.PreSerializeFilters.Add((swaggerDoc, httpReq) => swaggerDoc.Host = httpReq.Host.Value);
                    c.RouteTemplate = "{documentName}/swagger.json";
                });
                app.UseSwaggerUI(u =>
                {
                    u.SwaggerEndpoint("/ServiceApiTwo/swagger.json", "ServiceApiTwo");
                    u.DocumentTitle = "Service Api #2 文檔";
                });
            }

            // 允許網關訪問
            app.UseCors(options =>
            {
                options.WithOrigins("http://localhost:1999")
                .AllowAnyHeader()
                .AllowAnyMethod();
            });
            app.UseMvc();
        }

 

 使用IdentityServer4保護webapi

   先前已經創建IdentityServer項目,添加引用IdentityServer4.AspNetIdentity(2.5.0)、IdentityServer4.EntityFramework(2.5.0)。新建一個類IdentityServerConfig,裡面定義四個方法GetApiResources、GetIdentityResources、GetClients、GetTestUsers,具體代碼就不貼了,看一下Startup。生產環境的話,當然要用資料庫,這裡不討論IdentityServer4的使用。

public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

            services.AddIdentityServer()
                .AddDeveloperSigningCredential()
                .AddInMemoryPersistedGrants()
                .AddTestUsers(IdentityServerConfig.GetTestUsers())
                .AddInMemoryIdentityResources(IdentityServerConfig.GetIdentityResources())
                .AddInMemoryApiResources(IdentityServerConfig.GetApiResources())
                .AddInMemoryClients(IdentityServerConfig.GetClients(Configuration));
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseIdentityServer();

            app.UseMvc();
        }

  將網關和兩個api項目對應的ApiResources和Clients分別為api-gateway、service-api-one、service-api-two,兩個api客戶端AllowedScope為自己,網關的AllowedScope為自己和兩個api客戶端。在需要保護的三個項目中添加引用IdentityServer4.AccessTokenValidation(2.7.0),修改Startup的ConfigureServices,添加如下代碼。

//使用IdentityServer4
            services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
                .AddIdentityServerAuthentication(options =>
                {
                    options.ApiName = "service-api-two";
                    options.Authority = "http://localhost:16690"; // IdentityServer驗證服務
                    options.RequireHttpsMetadata = false;
                    options.EnableCaching = true;
                });

  Startup.Configure中添加app.UseAuthentication();

  要在swagger中訪問需要驗證的api,需要在swagger配置中添加安全驗證。

services.AddSwaggerGen(options =>
            {
                //SwaggerDoc的第一個參數要與Configure中SwaggerEndPoint中的版本名稱一致
                //既可以使用版本號,也可以使用自定義名稱
                options.SwaggerDoc("ServiceApiTwo", new Info
                {
                    Title = "Services.Api #two",
                    Version = "v1",
                    Description = "服務api #two",
                    License = new License
                    {
                        Name = "MIT",
                        Url = "https://mit-license.org/"
                    },
                    Contact = new Contact
                    {
                        Name = "原來是李",
                        Url = "http://www.cnblogs.com/falltakeman"
                    }
                });
                var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
                var xmlPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, xmlFile);
                options.IncludeXmlComments(xmlPath);
                // swagger訪問需要驗證的api
                options.AddSecurityDefinition("Bearer", new ApiKeyScheme
                {
                    In = "header",
                    Name = "Authorization",
                    Type = "apiKey",
                    Description = "Bearer {token}"
                });
                options.AddSecurityRequirement(new Dictionary<string, IEnumerable<string>>
                {
                    {
                        "Bearer",
                        Enumerable.Empty<string>()
                    }
                });
            });

  在api控制器中,在需要保護的api上添加[Authorize]特性,沒有授權的情況下訪問受限api會報401錯誤。

   使用postman獲取token,在swagger中填寫token,再次發起請求,響應正常。

   在ApiGateway的Startup.ConfigureServices添加Authentication,在Services.AddSwaggerGen添加相應代碼,啟動項目在app.UseOcelot().Wait()拋出異常:Scheme already exists: BearerIdentityServerAuthenticationJwt. 最終使用了下麵的方式。在ApiGateway項目中通過swagger也可以訪問業務api了。

Action<IdentityServerAuthenticationOptions> isaOpt = option =>
            {
                option.Authority = Configuration["IdentityService:Uri"];
                option.RequireHttpsMetadata = Convert.ToBoolean(Configuration["IdentityService:UseHttps"]);
                option.ApiName = Configuration["IdentityService:ApiName"];
                option.ApiSecret = Configuration["IdentityService:ApiSecret"];
                option.SupportedTokens = SupportedTokens.Both;
            };
            services.AddAuthentication().AddIdentityServerAuthentication(Configuration["IdentityService:DefaultScheme"], isaOpt);

  但是配置中的IdentityService:DefaultScheme不可以是"Bearer",試驗配置的是"IdentityBearer",不知為何不可以是"Bearer",不知道有沒有懂這個的可以指點一二。

 

 

the end...

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • glob模塊 提供了一個函數,用於匹配符合要求的文件: re模塊 字元串正則匹配 datetime模塊 日期時間 格式化輸出也可以這樣用: 數據壓縮 支持數據打包、壓縮的模塊:zlib,gzip,bz2,zipfile,以及 tarfile。 壓縮數據: 壓縮文件: 解壓文件: ...
  • 1、java gc 2、java class的載入過程 3、java hashmap、 為什麼用紅黑樹、紅黑樹鄰接點為啥是8 。 4、拜占庭問題 5、一致性哈希 6、如何控制負載均衡。 7、http碼 302 403 。 8、https 加密過程。 9、操作系統虛存實現原理,交換,覆蓋區別。 10、 ...
  • 出自:http://1t.click/7TJ 目錄: 案例背景引入 特殊的電商大促場景 抗住大促的瞬時壓力需要幾台機器? 大促高峰期訂單系統的記憶體使用模型估算 記憶體到底該如何分配? 新生代垃圾回收優化之一:Survivor空間夠不夠 新生代對象躲過多少次垃圾回收後進入老年代? 多大的對象直接進入老年 ...
  • 類與類的關係 依賴關係 組合關係 組合: 將一個類的對象封裝成另一個類的對象的屬性. 繼承關係 繼承的優點: 1,增加了類的耦合性(耦合性不宜多,宜精)。 2,減少了重覆代碼。 3,使得代碼更加規範化,合理化 繼承:可以分 單繼承,多繼承 。 單繼承 第一種:直接執行 第二種:子類和父類都有相同功能 ...
  • 什麼是MVC MVC : 模型、視圖、控制器 , 是一種軟體設計規範,說明不是設計模式; 本質:將業務邏輯 , 數據 , 顯示 分離的方式來編寫代碼; 前後端分離; Model:數據模型,提供要展示的數據,一般我們都會把這兩個分離開來 , 數據Dao,服務層Service。 View :負責進行數據 ...
  • 第五節 一、字典 python的數據結構之一 字典 —— dict 定義:dic = {"key":"dajjlad"} 作用:存儲數據,大量,將數據和數據起到關聯作用 字典是可變的數據類型,無序的 所有的操作都通過鍵 # 鍵:必須是不可變的數據類型(可哈希),且唯一 不可哈希就是可變數據類型# 值 ...
  • 個人一直覺得對學習任何知識而言,概念是相當重要的。掌握了概念和原理,細節可以留給實踐去推敲。掌握的關鍵在於理解,通過具體的實例和實際操作來感性的體會概念和原理可以起到很好的效果。本文通過一些具體的例子簡單介紹一下python的多線程和多進程,後續會寫一些進程通信和線程通信的一些文章。 python多 ...
  • "鏈接" A 求出來到每座山的距離後,就可以計算出每隻貓等待的時間與出發時間的關係。 如果出發時間為$x$,求出來只貓的等待時間。這裡用$b_i$表示第i只貓的等待時間。然後我們將這些時間排序。問題就轉化為了,從m個有序的數中,選出p個,每個數字覆蓋以其為開頭的一段區間。這段區間的貢獻為$x\tim ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...