ASP.NET Core Swagger接入使用IdentityServer4 的 WebApi

寫在前面

是這樣的,咱們如今接口使用了Ocelot作網關,Ocelot裏面集成了基於IdentityServer4開發的受權中心用於對Api資源的保護。問題來了,咱們的Api用了SwaggerUI作接口的自文檔,那就蛋疼了,你接入了IdentityServer4的Api,用SwaggerUI調試、調用接口的話,妥妥的401,未受權啊。那有小夥伴就會說了,你SwaggerUI的Api不通過網關不就ok了?誒,好辦法。可是:html

  1. 我不想改變Url規則啊,我是/api開頭的Url都是通過網關的,若是不通過網關要加端口或者改變Url規則,會給其餘部門的同事帶來麻煩(多個Url規則容易混淆);
  2. 另外是,由於生產環境是接入了IdentityServer4,我想測試環境從一開始就須要調用方熟悉接口的接入,避免平時用沒有通過受權中心的Url調試,一到生產就出問題。

ok,廢話講得有點多,咱們就直奔主題。git

下面咱們須要建立兩個示例項目:github

一、IdentityServer4的受權中心;web

二、使用SwaggerUI作自文檔的WebApi項目;json

寫得有點亂,本文源碼地址:
https://github.com/gebiWangshushu/cnblogs-demos/tree/master/SwggerUI.IdentityServer4.Exampleapi

構建基於IdentityServer4受權中心

一、新建空白解決方案,並添加一個空的WebApi項目,IdentityServer

1557495509700

二、引用包。

Install-Package IdentityServer4

三、添加配置類:Config.cs

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" }
                }
            };
        }
    }
}

四、修改Startup.cs

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,跑起來了瀏覽器

1557497033760

使用SwaggerUI作自文檔的WebApi項目

一、添加WebApi項目,SwaggerUIApi

如今項目結構這樣:安全

1557497204567

二、先添加SwaggerUI,先不接入IdentityServer

修改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

1557497953754

咱們調用一下接口:

槓槓的200:

1557497995457

三、接口項目咱們接入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,未受權;

1557498423814

三、接入IdentityServer

一、添加受權響應操做的過濾器,AuthResponsesOperationFilter.cs

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" } }}
                };
            }
        }
    }
}

二、修改Startup.cs ,ConfigureServices方法的,services.AddSwaggerGen()

配置成這樣:

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>();
            });

三、咱們還需給受權中心添加一個登錄界面

去: https://github.com/IdentityServer/IdentityServer4/tree/master/samples/Quickstarts/3_ImplicitFlowAuthentication/src/IdentityServer

下載這個兩個文件夾,複製丟到IdentityServer項目下面:

1557500638819

項目結構:1557500675473

四、咱們運行看看

先啓動Identityserver項目

運行SwaggerUI能夠看到,這兩個地方了個小鎖頭,表示已啓用安全保護:

1557500788279

咱們點一下上面的按鈕:

1557500876183

哇,咱們跳到了這裏:

1557501003686

輸入:alice/alice,點登陸:

哇哇:

1557501070248

固然是Yes啦,而後這邊變成這樣了:

1557501113274

這是已得到受權狀態,咱們再次調用看看:

1557501152535

這裏咱們看到已經調用成功,仔細看請求,與前面簡短的請求不一樣的是,如今請求裏面帶了access_token了,

這纔是咱們折騰這麼久得來的寶貝。

總結

寫得有點匆忙,但願你們能看得懂[捂臉];

源碼地址:https://github.com/gebiWangshushu/cnblogs-demos/tree/master/SwggerUI.IdentityServer4.Example

參考

https://github.com/domaindrivendev/Swashbuckle.AspNetCore

https://github.com/IdentityServer/IdentityServer4

相關文章
相關標籤/搜索