是這樣的,咱們如今接口使用了Ocelot作網關,Ocelot裏面集成了基於IdentityServer4開發的受權中心用於對Api資源的保護。問題來了,咱們的Api用了SwaggerUI作接口的自文檔,那就蛋疼了,你接入了IdentityServer4的Api,用SwaggerUI調試、調用接口的話,妥妥的401,未受權啊。那有小夥伴就會說了,你SwaggerUI的Api不通過網關不就ok了?誒,好辦法。可是:html
/api
開頭的Url都是通過網關的,若是不通過網關要加端口或者改變Url規則,會給其餘部門的同事帶來麻煩(多個Url規則容易混淆);ok,廢話講得有點多,咱們就直奔主題。git
下面咱們須要建立兩個示例項目:github
一、IdentityServer4的受權中心;web
二、使用SwaggerUI作自文檔的WebApi項目;json
寫得有點亂,本文源碼地址:
https://github.com/gebiWangshushu/cnblogs-demos/tree/master/SwggerUI.IdentityServer4.Exampleapi
Install-Package IdentityServer4
using IdentityServer4; using IdentityServer4.Models; using IdentityServer4.Test; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace IdentityServer { public static class Config { public static List<TestUser> GetUsers() { return new List<TestUser> { new TestUser { SubjectId = "1", Username = "alice", Password = "alice" } }; } public static IEnumerable<IdentityResource> GetIdentityResources() { return new IdentityResource[] { new IdentityResources.OpenId(), new IdentityResources.Profile(), }; } /// <summary> /// API信息 /// </summary> /// <returns></returns> public static IEnumerable<ApiResource> GetApis() { return new[] { new ApiResource("swagger_api", "Demo SwaggerUI integrat Idp") }; } /// <summary> /// 客服端信息 /// </summary> /// <returns></returns> public static IEnumerable<Client> GetClients() { return new[] { new Client { ClientId = "swagger_client",//客服端名稱 ClientName = "Swagger UI client",//描述 AllowedGrantTypes = GrantTypes.Implicit,//Implicit 方式 AllowAccessTokensViaBrowser = true,//是否經過瀏覽器爲此客戶端傳輸訪問令牌 RedirectUris = { "http://localhost:5001/swagger/oauth2-redirect.html" }, AllowedScopes = { "swagger_api" } } }; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace IdentityServer { public class Startup { public IHostingEnvironment Environment { get; } public Startup(IHostingEnvironment environment) { Environment = environment; } public void ConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); var builder = services.AddIdentityServer() .AddInMemoryIdentityResources(Config.GetIdentityResources()) .AddInMemoryApiResources(Config.GetApis()) .AddInMemoryClients(Config.GetClients()) .AddTestUsers(Config.GetUsers()); if (Environment.IsDevelopment()) { builder.AddDeveloperSigningCredential(); } else { throw new Exception("need to configure key material"); } } // 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.UseIdentityServer(); app.UseMvcWithDefaultRoute(); } } }
ok,跑起來了瀏覽器
如今項目結構這樣:安全
修改Startup.cs服務器
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Swashbuckle.AspNetCore.Swagger; namespace SwggerUIApi { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new Info { Version = "v1", Title = "ToDo API", Description = "A simple example ASP.NET Core Web API", TermsOfService = "None", Contact = new Contact { Name = "Shayne Boyer", Email = string.Empty, Url = "https://twitter.com/spboyer" }, License = new License { Name = "Use under LICX", Url = "https://example.com/license" } }); var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); c.IncludeXmlComments(xmlPath); }); } // 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.UseSwagger(); // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.), // specifying the Swagger JSON endpoint. app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); }); app.UseMvc(); } } }
獲得這樣的SwaggerUI:app
咱們調用一下接口:
槓槓的200:
三、接口項目咱們接入IdentityServer4
修改:Startup.cs ,ConfigureServices方法,
services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme) .AddIdentityServerAuthentication(options => { options.Authority = "http://localhost:5000"; // IdentityServer服務器地址 options.ApiName = "swagger_api"; // 用於針對進行身份驗證的API資源的名稱 options.RequireHttpsMetadata = false; // 指定是否爲HTTPS });
修改:Startup.cs ,Configure方法
app.UseAuthentication();
Ok,能夠看到咱們接口接入IdentityServer了。提示401,未受權;
using Microsoft.AspNetCore.Authorization; using Swashbuckle.AspNetCore.Swagger; using Swashbuckle.AspNetCore.SwaggerGen; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace SwggerUIApi { public class AuthResponsesOperationFilter : IOperationFilter { public void Apply(Operation operation, OperationFilterContext context) { //獲取是否添加登陸特性 var authAttributes = context.MethodInfo.DeclaringType.GetCustomAttributes(true) .Union(context.MethodInfo.GetCustomAttributes(true)) .OfType<AuthorizeAttribute>().Any(); if (authAttributes) { operation.Responses.Add("401", new Response { Description = "暫無訪問權限" }); operation.Responses.Add("403", new Response { Description = "禁止訪問" }); operation.Security = new List<IDictionary<string, IEnumerable<string>>> { new Dictionary<string, IEnumerable<string>> {{"oauth2", new[] { "swagger_api" } }} }; } } } }
配置成這樣:
services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new Info { Version = "v1", Title = "ToDo API", Description = "A simple example ASP.NET Core Web API", TermsOfService = "None", Contact = new Contact { Name = "Shayne Boyer", Email = string.Empty, Url = "https://twitter.com/spboyer" }, License = new License { Name = "Use under LICX", Url = "https://example.com/license" } }); var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); c.IncludeXmlComments(xmlPath); //接入identityserver c.AddSecurityDefinition("oauth2", new OAuth2Scheme { Flow = "implicit", // 只需經過瀏覽器獲取令牌(適用於swagger) AuthorizationUrl = "http://localhost:5000/connect/authorize",//獲取登陸受權接口 Scopes = new Dictionary<string, string> { { "swagger_api_scopde", "swagger_api access" }//指定客戶端請求的api做用域。 若是爲空,則客戶端沒法訪問 } }); c.OperationFilter<AuthResponsesOperationFilter>(); });
下載這個兩個文件夾,複製丟到IdentityServer項目下面:
項目結構:
先啓動Identityserver項目
運行SwaggerUI能夠看到,這兩個地方了個小鎖頭,表示已啓用安全保護:
咱們點一下上面的按鈕:
哇,咱們跳到了這裏:
輸入:alice/alice,點登陸:
哇哇:
固然是Yes啦,而後這邊變成這樣了:
這是已得到受權狀態,咱們再次調用看看:
這裏咱們看到已經調用成功,仔細看請求,與前面簡短的請求不一樣的是,如今請求裏面帶了access_token了,
這纔是咱們折騰這麼久得來的寶貝。
寫得有點匆忙,但願你們能看得懂[捂臉];
源碼地址:https://github.com/gebiWangshushu/cnblogs-demos/tree/master/SwggerUI.IdentityServer4.Example