IdentityServer4+API+Swagger整合

最近想整合IdentityServer4跟API,但網上找到的都是各類坑,踩都踩不玩!html

花了點時間終於整合好了,記錄下。git

新建空的asp.net core 項目

使用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"
                }
            };
        }
    }
}
View Code

注入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

添加Swagge

使用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

相關文章
相關標籤/搜索