最近想整合IdentityServer4跟API,但網上找到的都是各類坑,踩都踩不玩!html
花了點時間終於整合好了,記錄下。git
使用NuGet安裝IdentityServer4最新版4.1.0。安裝完成新建Config.cs類。內容以下:github
using IdentityServer4; using IdentityServer4.Models; using IdentityServer4.Test; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace IdsAPI { public static class Config { /// <summary> /// 客戶端 /// </summary> /// <returns></returns> internal static IEnumerable<Client> Clients() { yield return new Client { ClientId = "test-id", ClientName = "Test client (Code with PKCE)", RedirectUris = new[] { "http://localhost:5000/resource-server/swagger/oauth2-redirect.html", // Kestrel }, ClientSecrets = { new Secret("test-secret".Sha256()) }, RequireConsent = true, AllowedGrantTypes = GrantTypes.Code, RequirePkce = true, AllowedScopes = new[] { "api",IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile}, }; } /// <summary> /// api資源 /// </summary> /// <returns></returns> internal static IEnumerable<ApiResource> ApiResources() { return new List<ApiResource> { new ApiResource("api","my api") { Scopes ={"api"},//重要,不配置返回 invalid_scope } }; } /// <summary> /// api範圍 /// </summary> /// <returns></returns> internal static IEnumerable<ApiScope> GetApiScopes() { return new List<ApiScope> { new ApiScope("api") }; } internal static IEnumerable<IdentityResource> GetIdentityResourceResources() { return new List<IdentityResource> { new IdentityResources.OpenId(), new IdentityResources.Profile() }; } /// <summary> /// 測試用戶 /// </summary> /// <returns></returns> internal static List<TestUser> TestUsers() { return new List<TestUser> { new TestUser { SubjectId = "joebloggs", Username = "admin", Password = "123456" } }; } } }
注入IdentityServer4,代碼以下:json
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; namespace IdentityServer4API { public class Startup { // This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { //注入IdentityServer services.AddIdentityServer() .AddDeveloperSigningCredential() .AddInMemoryClients(Config.Clients()) .AddInMemoryApiResources(Config.ApiResources()) .AddTestUsers(Config.TestUsers()) .AddInMemoryIdentityResources(Config.GetIdentityResourceResources()) //4.0版本須要添加,否則調用時提示invalid_scope錯誤 .AddInMemoryApiScopes(Config.GetApiScopes()); //注入mvc services.AddControllersWithViews(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } //添加靜態資源引用 app.UseStaticFiles(); app.UseRouting(); //添加IdentityServer app.UseIdentityServer(); app.UseEndpoints(endpoints => { endpoints.MapDefaultControllerRoute(); }); } } }
啓動訪問 http://localhost:5000/.well-known/openid-configuration 能正常訪問便可。windows
使用NuGet安裝IdentityServer4.AccessTokenValidation跟Swashbuckle.AspNetCore最新版。api
新建類SecurityRequirementsOperationFilter,內容以下:服務器
using Microsoft.AspNetCore.Authorization; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace IdentityServer4API { public class SecurityRequirementsOperationFilter : IOperationFilter { public void Apply(OpenApiOperation operation, OperationFilterContext context) { //獲取是否添加登陸特性 //策略名稱映射到範圍 var requiredScopes = context.MethodInfo .GetCustomAttributes(true) .OfType<AuthorizeAttribute>() .Select(attr => attr.Policy) .Distinct(); if (requiredScopes.Any()) { operation.Responses.Add("401", new OpenApiResponse { Description = "未經受權" }); operation.Responses.Add("403", new OpenApiResponse { Description = "禁止訪問" }); var oAuthScheme = new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" } }; operation.Security = new List<OpenApiSecurityRequirement> { new OpenApiSecurityRequirement { [ oAuthScheme ] = requiredScopes.ToList() } }; } } } }
修改Startup中 ConfigureServices方法,增長新的配置:mvc
//身份驗證設置有點細微差異,由於此應用提供了身份驗證服務器和資源服務器 //默認狀況下使用「 Cookies」方案,而且在資源服務器控制器中明確要求「 Bearer」 //詳細查看 https://docs.microsoft.com/en-us/aspnet/core/security/authorization/limitingidentitybyscheme?tabs=aspnetcore2x services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie() .AddIdentityServerAuthentication(c => { c.Authority = "http://localhost:5000/"; c.RequireHttpsMetadata = false; c.ApiName = "api"; }); //配置直接映射到OAuth2.0範圍的命名身份驗證策略 services.AddAuthorization(c => { c.AddPolicy("AuthorizedAccess", p => p.RequireClaim("scope", "api")); }); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Version = "v1", Title = "Test API V1" }); // 定義正在使用的OAuth2.0方案 c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme { Type = SecuritySchemeType.OAuth2, Flows = new OpenApiOAuthFlows { AuthorizationCode = new OpenApiOAuthFlow { AuthorizationUrl = new Uri("/connect/authorize", UriKind.Relative), TokenUrl = new Uri("/connect/token", UriKind.Relative), Scopes = new Dictionary<string, string> { { "api", "受權讀寫操做" }, } } } }); // 根據AuthorizeAttributea分配是否須要受權操做 c.OperationFilter<SecurityRequirementsOperationFilter>(); });
修改改Configure,增長配置,完整代碼以下:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } //添加靜態資源引用 app.UseStaticFiles(); app.UseRouting(); //身份驗證 app.UseAuthentication(); app.UseAuthorization(); //添加IdentityServer app.UseIdentityServer(); app.UseEndpoints(endpoints => { endpoints.MapDefaultControllerRoute(); }); //api配置 app.Map("/resource-server", resourceServer => { resourceServer.UseRouting(); //身份驗證 resourceServer.UseAuthentication(); resourceServer.UseAuthorization(); // resourceServer.UseEndpoints(endpoints => { endpoints.MapControllers(); }); //Swagger resourceServer.UseSwagger(); resourceServer.UseSwaggerUI(c => { c.SwaggerEndpoint("/resource-server/swagger/v1/swagger.json", "My API V1"); c.EnableDeepLinking(); // Additional OAuth settings (See https://github.com/swagger-api/swagger-ui/blob/v3.10.0/docs/usage/oauth2.md) c.OAuthClientId("test-id"); c.OAuthClientSecret("test-secret"); c.OAuthAppName("test-app"); c.OAuthScopeSeparator(" "); c.OAuthUsePkce(); }); }); }
修改Properties下的launchSettings啓動配置文件:app
{ "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:8950", "sslPort": 44380 } }, "profiles": { "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, "IdentityServer4API": { "commandName": "Project", "launchBrowser": true, "launchUrl": "resource-server/swagger",//初始頁 "applicationUrl": "http://localhost:5000", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } } }
新建api控制器:asp.net
using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; namespace API.Controllers { [Route("products")] public class ProductsController : Controller { [HttpGet] [Authorize(AuthenticationSchemes = "Bearer")] [Authorize("AuthorizedAccess")] public IEnumerable<Product> GetProducts() { yield return new Product { Id = 1, SerialNo = "ABC123", }; } [HttpGet("{id}")] public Product GetProduct(int id) { return new Product { Id = 1, SerialNo = "ABC123", }; } [HttpPost] public void CreateProduct([FromBody]Product product) { } [HttpDelete("{id}")] public void DeleteProduct(int id) { } } public class Product { public int Id { get; internal set; } public string SerialNo { get; set; } public ProductStatus Status { get; set; } } public enum ProductStatus { InStock, ComingSoon } }
啓動後咱們能夠看到加了Authorize的方法有一把瑣同樣的圖標
這樣的接口須要登陸才能正常使用,不登陸受權調用返回401,無效受權錯誤。
點擊瑣或者Authorize按鈕顯示以下界面,勾選對應的api名稱,
在次點擊Authorize會跳轉到登陸頁面,登陸在config種配置的用戶會跳到受權頁面受權後返回api接口頁面。
這是完成受權後的界面
在次調用api就能正常調用:
演示源碼地址:https://github.com/ice-ko/IdentityServer4-API-Swagger