zoukankan      html  css  js  c++  java
  • ASP.NET Core Swagger接入使用IdentityServer4 的 WebApi

    写在前面

    是这样的,我们现在接口使用了Ocelot做网关,Ocelot里面集成了基于IdentityServer4开发的授权中心用于对Api资源的保护。问题来了,我们的Api用了SwaggerUI做接口的自文档,那就蛋疼了,你接入了IdentityServer4的Api,用SwaggerUI调试、调用接口的话,妥妥的401,未授权啊。那有小伙伴就会说了,你SwaggerUI的Api不经过网关不就ok了?诶,好办法。但是:

    1. 我不想改变Url规则啊,我是/api开头的Url都是经过网关的,如果不经过网关要加端口或者改变Url规则,会给其他部门的同事带来麻烦(多个Url规则容易混淆);
    2. 另外是,因为生产环境是接入了IdentityServer4,我想测试环境从一开始就需要调用方熟悉接口的接入,避免平时用没有经过授权中心的Url调试,一到生产就出问题。

    ok,废话讲得有点多,我们就直奔主题。

    下面我们需要创建两个示例项目:

    1、IdentityServer4的授权中心;

    2、使用SwaggerUI做自文档的WebApi项目;

    写得有点乱,本文源码地址:
    https://github.com/gebiWangshushu/cnblogs-demos/tree/master/SwggerUI.IdentityServer4.Example

    构建基于IdentityServer4授权中心

    1、新建空白解决方案,并添加一个空的WebApi项目,IdentityServer

    1557495509700

    2、引用包。

    Install-Package IdentityServer4
    

    3、添加配置类: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" }
                    }
                };
            }
        }
    }
    
    

    4、修改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项目

    1、添加WebApi项目,SwaggerUIApi

    现在项目结构这样:

    1557497204567

    2、先添加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:

    1557497953754

    我们调用一下接口:

    杠杠的200:

    1557497995457

    3、接口项目我们接入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

    3、接入IdentityServer

    1、添加授权响应操作的过滤器,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" } }}
                    };
                }
            }
        }
    }
    
    

    2、修改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>();
                });
    

    3、我们还需给授权中心添加一个登陆界面

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

    下载这个两个文件夹,复制丢到IdentityServer项目下面:

    1557500638819

    项目结构:1557500675473

    4、我们运行看看

    先启动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

  • 相关阅读:
    Linux下打包发布Qt应用程序
    嵌入式中的BSP---BSP到底是什么?
    (转)Spring 工具类 ConfigurationClassParser 分析得到配置类 -- springboot一样处理过程
    React Hooks之useState、useEffect使用
    数组排序多种方法汇总
    封装判断浏览器是否是IE浏览器
    封装addEventListener,removeEventListener指定元素添加事件及兼容问题js
    js判断是否超过几行
    react日期格式化组件
    Windows smynesc免费经典儿时小游戏分享给大家
  • 原文地址:https://www.cnblogs.com/xiaxiaolu/p/10847248.html
Copyright © 2011-2022 走看看