|
|
|
@ -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<AddResponseHeadersFilter>(); |
|
|
|
|
c.OperationFilter<AppendAuthorizeToSummaryOperationFilter>(); |
|
|
|
|
|
|
|
|
|
// 在header中添加token,传递到后台 |
|
|
|
|
c.OperationFilter<SecurityRequirementsOperationFilter>(); |
|
|
|
|
|
|
|
|
|
// 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<AddResponseHeadersFilter>(); |
|
|
|
|
c.OperationFilter<AppendAuthorizeToSummaryOperationFilter>(); |
|
|
|
|
|
|
|
|
|
// 在header中添加token,传递到后台 |
|
|
|
|
c.OperationFilter<SecurityRequirementsOperationFilter>(); |
|
|
|
|
c.MapType<QueryFilter>(() => 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<string>() |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
}); |
|
|
|
|
services.AddSwaggerGenNewtonsoftSupport(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static void UseSwaggerMiddle(this IApplicationBuilder app, Func<Stream> 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 = ""; |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
/// 当前API版本 |
|
|
|
|
/// </summary> |
|
|
|
|
private static readonly string version = $"V1.0"; |
|
|
|
|
/// <summary> |
|
|
|
|
/// Swagger分组信息,将进行遍历使用 |
|
|
|
|
/// </summary> |
|
|
|
|
private static readonly List<SwaggerApiInfo> ApiInfos = new List<SwaggerApiInfo>() |
|
|
|
|
{ |
|
|
|
|
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 |
|
|
|
|
{ |
|
|
|
|
/// <summary> |
|
|
|
|
/// URL前缀 |
|
|
|
|
/// </summary> |
|
|
|
|
public string UrlPrefix { get; set; } |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
/// 名称 |
|
|
|
|
/// </summary> |
|
|
|
|
public string Name { get; set; } |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
/// OpenApiInfo |
|
|
|
|
/// </summary> |
|
|
|
|
public OpenApiInfo OpenApiInfo { get; set; } |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
/// swagger分组 |
|
|
|
|
/// </summary> |
|
|
|
|
public static class Grouping |
|
|
|
|
{ |
|
|
|
|
/// <summary> |
|
|
|
|
/// 系统 |
|
|
|
|
/// </summary> |
|
|
|
|
public const string GroupName_System = "system"; |
|
|
|
|
/// <summary> |
|
|
|
|
/// 认证授权 |
|
|
|
|
/// </summary> |
|
|
|
|
public const string GroupName_Auth = "auth"; |
|
|
|
|
/// <summary> |
|
|
|
|
/// 其他 |
|
|
|
|
/// </summary> |
|
|
|
|
public const string GroupName_Other = "other"; |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
/// Ghra |
|
|
|
|
/// </summary> |
|
|
|
|
public const string GroupName_Ghra = "Ghra"; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
@ -114,6 +262,10 @@ namespace Tiobon.Core.Extensions |
|
|
|
|
/// </summary> |
|
|
|
|
public enum ApiVersions |
|
|
|
|
{ |
|
|
|
|
/// <summary> |
|
|
|
|
/// Ghra 版本 |
|
|
|
|
/// </summary> |
|
|
|
|
Ghra = 0, |
|
|
|
|
/// <summary> |
|
|
|
|
/// V1 版本 |
|
|
|
|
/// </summary> |
|
|
|
|