diff --git a/Tiobon.Core.Extensions/Middlewares/SwaggerMiddleware.cs b/Tiobon.Core.Extensions/Middlewares/SwaggerMiddleware.cs deleted file mode 100644 index 049549ea..00000000 --- a/Tiobon.Core.Extensions/Middlewares/SwaggerMiddleware.cs +++ /dev/null @@ -1,54 +0,0 @@ -using Tiobon.Core.Common; -using Microsoft.AspNetCore.Builder; -using Swashbuckle.AspNetCore.SwaggerUI; -using System; -using System.IO; -using System.Linq; -using Serilog; -using static Tiobon.Core.Extensions.CustomApiVersion; - -namespace Tiobon.Core.Extensions.Middlewares -{ - /// - /// Swagger中间件 - /// - public static class SwaggerMiddleware - { - public static void UseSwaggerMiddle(this IApplicationBuilder app, Func streamHtml) - { - if (app == null) throw new ArgumentNullException(nameof(app)); - - app.UseSwagger(); - app.UseSwaggerUI(c => - { - //根据版本名称倒序 遍历展示 - var apiName = AppSettings.app(new string[] { "Startup", "ApiName" }); - typeof(ApiVersions).GetEnumNames().OrderByDescending(e => e).ToList().ForEach(version => { c.SwaggerEndpoint($"/swagger/{version}/swagger.json", $"{apiName} {version}"); }); - - c.SwaggerEndpoint($"https://petstore.swagger.io/v2/swagger.json", $"{apiName} pet"); - - // 将swagger首页,设置成我们自定义的页面,记得这个字符串的写法:{项目名.index.html} - if (streamHtml.Invoke() == null) - { - var msg = "index.html的属性,必须设置为嵌入的资源"; - Log.Error(msg); - throw new Exception(msg); - } - - c.IndexStream = streamHtml; - c.DocExpansion(DocExpansion.None); //->修改界面打开时自动折叠 - - if (Permissions.IsUseIds4) - { - c.OAuthClientId("Tiobonadminjs"); - } - - //增加令牌本地缓存 reload不会丢失 - c.ConfigObject.AdditionalItems.Add("persistAuthorization","true"); - - // 路径配置,设置为空,表示直接在根域名(localhost:8001)访问该文件,注意localhost:8001/swagger是访问不到的,去launchSettings.json把launchUrl去掉,如果你想换一个路径,直接写名字即可,比如直接写c.RoutePrefix = "doc"; - c.RoutePrefix = ""; - }); - } - } -} \ No newline at end of file diff --git a/Tiobon.Core.Extensions/ServiceExtensions/SwaggerSetup.cs b/Tiobon.Core.Extensions/ServiceExtensions/SwaggerSetup.cs index a2234bce..a144426b 100644 --- a/Tiobon.Core.Extensions/ServiceExtensions/SwaggerSetup.cs +++ b/Tiobon.Core.Extensions/ServiceExtensions/SwaggerSetup.cs @@ -9,6 +9,9 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices; using static Tiobon.Core.Extensions.CustomApiVersion; +using Microsoft.AspNetCore.Builder; +using Swashbuckle.AspNetCore.SwaggerUI; +using Microsoft.Extensions.Options; namespace Tiobon.Core.Extensions { @@ -22,48 +25,35 @@ namespace Tiobon.Core.Extensions if (services == null) throw new ArgumentNullException(nameof(services)); var basePath = AppContext.BaseDirectory; - //var basePath2 = Microsoft.DotNet.PlatformAbstractions.ApplicationEnvironment.ApplicationBasePath; - var ApiName = AppSettings.app(new string[] { "Startup", "ApiName" }); services.AddSwaggerGen(c => { - //遍历出全部的版本,做文档信息展示 - typeof(ApiVersions).GetEnumNames().ToList().ForEach(version => + ApiInfos.ForEach(x => { - c.SwaggerDoc(version, new OpenApiInfo - { - Version = version, - Title = $"{ApiName} 接口文档——{RuntimeInformation.FrameworkDescription}", - Description = $"{ApiName} HTTP API " + version, - //Contact = new OpenApiContact { Name = ApiName, Email = "Tiobon.Core@xxx.com", Url = new Uri("https://neters.club") }, - //License = new OpenApiLicense { Name = ApiName + " 官方文档", Url = new Uri("http://apk.neters.club/.doc/") } - }); + c.SwaggerDoc(x.UrlPrefix, x.OpenApiInfo); c.OrderActionsBy(o => o.RelativePath); }); - c.UseInlineDefinitionsForEnums(); + // 开启加权小锁 + c.OperationFilter(); + c.OperationFilter(); + + // 在header中添加token,传递到后台 + c.OperationFilter(); + + // API注释所需XML文件 try { - //这个就是刚刚配置的xml文件名 - var xmlPath = Path.Combine(basePath, "Tiobon.Core.xml"); - //默认的第二个参数是false,这个是controller的注释,记得修改 - c.IncludeXmlComments(xmlPath, true); - - //这个就是Model层的xml文件名 - var xmlModelPath = Path.Combine(basePath, "Tiobon.Core.Model.xml"); - c.IncludeXmlComments(xmlModelPath); + + c.IncludeXmlComments(Path.Combine(basePath, "Tiobon.Core.xml"), true); + c.IncludeXmlComments(Path.Combine(basePath, "Tiobon.Core.Model.xml"), true); } catch (Exception ex) { Log.Error("Tiobon.Core.xml和Tiobon.Core.Model.xml 丢失,请检查并拷贝。\n" + ex.Message); } - // 开启加权小锁 - c.OperationFilter(); - c.OperationFilter(); - - // 在header中添加token,传递到后台 - c.OperationFilter(); + c.MapType(() => new OpenApiSchema { Type = "string", Format = "string" }); // ids4和jwt切换 @@ -90,18 +80,176 @@ namespace Tiobon.Core.Extensions } else { - // Jwt Bearer 认证,必须是 oauth2 - c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme + c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { + Name = "Authorization", + Type = SecuritySchemeType.ApiKey, + BearerFormat = "JWT", + In = ParameterLocation.Header, + Scheme = "Bearer", Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}(注意两者之间是一个空格)\"", - Name = "Authorization", //jwt默认的参数名称 - In = ParameterLocation.Header, //jwt默认存放Authorization信息的位置(请求头中) - Type = SecuritySchemeType.ApiKey + }); } + + c.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "Bearer" + } + }, + new List() + } + }); + }); services.AddSwaggerGenNewtonsoftSupport(); } + + public static void UseSwaggerMiddle(this IApplicationBuilder app, Func streamHtml) + { + if (app == null) throw new ArgumentNullException(nameof(app)); + + SwaggerBuilderExtensions.UseSwagger(app); + app.UseSwaggerUI(options => + { + // 遍历分组信息,生成Json + ApiInfos.ForEach(x => + { + options.SwaggerEndpoint($"/swagger/{x.UrlPrefix}/swagger.json", x.Name); + }); + // 模型的默认扩展深度,设置为 -1 完全隐藏模型 + options.DefaultModelsExpandDepth(-1); + // API文档仅展开标记 + options.DocExpansion(DocExpansion.List); + // API前缀设置为空 + options.RoutePrefix = string.Empty; + // API页面Title + options.DocumentTitle = "接口文档"; + if (streamHtml.Invoke() == null) + { + var msg = "index.html的属性,必须设置为嵌入的资源"; + Log.Error(msg); + throw new Exception(msg); + } + + options.IndexStream = streamHtml; + options.DocExpansion(DocExpansion.None); //->修改界面打开时自动折叠 + + if (Permissions.IsUseIds4) + { + options.OAuthClientId("Tiobonadminjs"); + } + + //增加令牌本地缓存 reload不会丢失 + options.ConfigObject.AdditionalItems.Add("persistAuthorization", "true"); + + // 路径配置,设置为空,表示直接在根域名(localhost:8001)访问该文件,注意localhost:8001/swagger是访问不到的,去launchSettings.json把launchUrl去掉,如果你想换一个路径,直接写名字即可,比如直接写c.RoutePrefix = "doc"; + options.RoutePrefix = ""; + }); + } + + + /// + /// 当前API版本 + /// + private static readonly string version = $"V1.0"; + /// + /// Swagger分组信息,将进行遍历使用 + /// + private static readonly List ApiInfos = new List() + { + new SwaggerApiInfo + { + UrlPrefix = Grouping.GroupName_Auth, + Name = "认证授权", + OpenApiInfo = new OpenApiInfo + { + Version = version, + Title = "认证授权", + Description = "登录/注销", + } + }, + new SwaggerApiInfo + { + UrlPrefix = Grouping.GroupName_System, + Name = "系统模块", + OpenApiInfo = new OpenApiInfo + { + Version = version, + Title = "系统模块", + Description = "用户/角色/权限...", + } + }, + new SwaggerApiInfo + { + UrlPrefix = Grouping.GroupName_Other, + Name = "其他模块", + OpenApiInfo = new OpenApiInfo + { + Version = version, + Title = "其他模块", + Description = "其他...", + } + }, + new SwaggerApiInfo + { + UrlPrefix = Grouping.GroupName_Ghra, + Name = "Ghra模块", + OpenApiInfo = new OpenApiInfo + { + Version = version, + Title = "Ghra模块", + Description = "Ghra...", + } + } + }; + private class SwaggerApiInfo + { + /// + /// URL前缀 + /// + public string UrlPrefix { get; set; } + + /// + /// 名称 + /// + public string Name { get; set; } + + /// + /// OpenApiInfo + /// + public OpenApiInfo OpenApiInfo { get; set; } + } + + /// + /// swagger分组 + /// + public static class Grouping + { + /// + /// 系统 + /// + public const string GroupName_System = "system"; + /// + /// 认证授权 + /// + public const string GroupName_Auth = "auth"; + /// + /// 其他 + /// + public const string GroupName_Other = "other"; + + /// + /// Ghra + /// + public const string GroupName_Ghra = "Ghra"; + } } /// @@ -114,6 +262,10 @@ namespace Tiobon.Core.Extensions /// public enum ApiVersions { + /// + /// Ghra 版本 + /// + Ghra = 0, /// /// V1 版本 ///