“Blog.Core-master”程序没有使用.Net7框架内置的index.html页对api方法进行渲染显示,而是通过对“Swagger”和“SwaggerUI”内置中间件的自定义操作,调用根目录下的自定义index.html页对api方法进行渲染显示。
1、自定义“Swagger”和“SwaggerUI”内置中间件和index.html页
1.1 自定义“Swagger”和“SwaggerUI”内置中间件
using System;
using System.IO;
using System.Linq;
using Common.Helper;
using log4net;
//Nuget--Swashbuckle.AspNetCore
using Microsoft.AspNetCore.Builder;
//using static Blog.Core.Extensions.CustomApiVersion;
namespace Extensions.ServiceExtensions
{
/// <summary>
/// 【Swagger中间件】
/// <remarks>
/// 摘要:
/// 通过该类中的方法成员把“UseSwagger”管道中间件,集成到.Net7框架内置管道中,为页面渲染显示api提供支撑。
/// </remarks>
/// </summary>
public static class SwaggerMiddleware
{
private static readonly ILog Log = LogManager.GetLogger(typeof(SwaggerMiddleware));
public static void UseSwaggerMiddle(this IApplicationBuilder app, Func<Stream> streamHtml)
{
if (app == null) throw new ArgumentNullException(nameof(app));
//把“UseSwagger”管道中间件,集成到.Net7框架内置管道中。
app.UseSwagger();
//通过自定义设置“UseSwaggerUI”管道中间件,并集成到.Net7框架内置管道中,为页面渲染显示api提供支撑。
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展示api首页,设置成我们自定义的页面(这里特指:WebApi\index.html,记得这个字符串的写法:{项目名.index.html}
if (streamHtml.Invoke() == null)
{
var msg = "index.html的属性,必须设置为:“嵌入的资源”";
Log.Error(msg);
throw new Exception(msg);
}
c.IndexStream = streamHtml;
//if (Permissions.IsUseIds4)
//{
// c.OAuthClientId("blogadminjs");
//}
// 注意路径配置,设置为空,表示对根目录下的文件(这里特指:WebApi\index.html)进行访问;如果不定义正面的语句将会出现“404”错误。
c.RoutePrefix = "";
});
}
}
}
1.2自定义根目录Index.html页
注意:1、根目录Index.html页面的属性必须被设定为:“嵌入的资源”,如下图所示;
2、注释掉“launchSettings.json”文件中的"launchUrl"节点;或把“"launchUrl": "swagger"”修改为:“"launchUrl": "indexer.html"” ,如下图所示;
1.3 重构Program类
var app = builder.Build();
//把自定义管道中间件集成到.Net(Core)框架内置管道中,解决vue/uni-app前端项目(Cors)访问当前后端项目时,浏览器或App中出现的异常:
// 1、“has been blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.”。
// 2、“has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.”。
app.UseMiddleware<CorsMiddleware>();
//把自定义“UseSwagger”和“UseSwaggerUI”管道中间件集成到.Net7框架内置管道中,为自定义“index.html”页面渲染显示api提供支撑。
app.UseSwaggerMiddle(() => Assembly.GetExecutingAssembly().GetManifestResourceStream("WebApi.index.html"));
按F5执行程序如下图所示:
2 自定义“UseSwaggerAuthorized”中间件和swg-login.html页
2.1 复制资源文件到“wwwroot”目录,如下图所示:
2.2 自定义UseSwaggerAuthorized中间件
using System.Net;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
namespace Extensions.ServiceExtensions
{
/// <summary>
/// 【Swagger授权中间件】
/// </summary>
/// <remarks>
/// 摘要:
/// 该管道中间件类主要用于判断1个指定用户是否已经被授权,如果已经被授权则直接访问默认启动页面;反之跳转到登录页面。
/// </remarks>
public class SwaggerAuthMiddleware
{
#region 拷贝构造方法与变量
/// <summary>
/// 【下1个】
/// </summary>
/// <remarks>
/// 摘要:
/// .Net(Core)框架内置管道中的下1个管道中间件实例。
/// </remarks>
private readonly RequestDelegate next;
///<param name="next">.Net(Core)框架内置管道中的下1个管道中间件实例。</param>
/// <summary>
/// 【拷贝构造方法】
/// </summary>
/// <remarks>
/// 摘要:
/// 通过该构造方法中的参数实例,实例化.Net(Core)框架内置管道中的下1个管道中间件实例。
/// </remarks>
public SwaggerAuthMiddleware(RequestDelegate next)
{
this.next = next;
}
#endregion
#region 方法
///<param name="context">HTTP上下文实例。</param>
/// <summary>
/// 【异步调用】
/// </summary>
/// <remarks>
/// 摘要:
/// 通过该方法向.Net(Core)框架内置管道中集成当前管道中间件,判断1个指定用户是否已经被授权,如果已经被授权则直接访问默认启动页面;反之跳转到登录页面:
/// </remarks>
public async Task InvokeAsync(HttpContext context)
{
// 也可以根据是否是本地做判断 IsLocalRequest。
// 说明:该“index.html”页面即不是根目录中的“index.html”页面;也不是“wwwroot”目录中的“index.html”页面,它是“Swagger”中间件内置的“index.html”页面。
//所以只要当前程序集成了“Swagger”中间件,下面1行语句的值总为:true。
if (context.Request.Path.Value.ToLower().Contains("index.html"))
{
// 判断权限是否正确
if (IsAuthorized(context))
{
await next.Invoke(context);
return;
}
// 无权限,跳转swagger登录页
context.Response.Redirect("/swg-login.html");
}
else
{
await next.Invoke(context);
}
}
///<param name="context">HTTP上下文实例。</param>
/// <summary>
/// 【已授权?】
/// <remarks>
/// 摘要:
/// 通过对服务器端的“session”中指定信息的匹配操作,获取1个值false(未授权)/true(已授权),该值指示指定用户是否已经被授权。
/// </remarks>
/// <returns>
/// 返回:
/// 1个值false(未授权)/true(已授权)。
/// </returns>
/// </summary>
public bool IsAuthorized(HttpContext context)
{
// 使用session模式
// 可以使用其他的
return context.Session.GetString("swagger-code") == "success";
}
///<param name="context">HTTP上下文实例。</param>
/// <summary>
/// 【本地请求?】
/// <remarks>
/// 摘要:
/// 获取1个值false(非本地请求)/true(本地请求),该值指示指定请求是否是本地请求,如果不是swagger中间件将自动执行拦截操作。
/// 注意:
/// 该方法原程序中没有任何对象进行调用,如果简化定义实现可以直接删除掉。
/// </remarks>
/// <returns>
/// 返回:
/// 1个值false(非本地请求)/true(本地请求)
/// </returns>
/// </summary>
public bool IsLocalRequest(HttpContext context)
{
if (context.Connection.RemoteIpAddress == null && context.Connection.LocalIpAddress == null)
{
return true;
}
if (context.Connection.RemoteIpAddress.Equals(context.Connection.LocalIpAddress))
{
return true;
}
if (IPAddress.IsLoopback(context.Connection.RemoteIpAddress))
{
return true;
}
return false;
}
#endregion
}
/// <summary>
/// 【Swagger授权中间件扩展】
/// </summary>
/// <remarks>
/// 摘要:
/// 通过该类中的方法成员把Swagger授权中间件集成到.Net7框架的内置管道中,以实现,如果已经被授权则直接访问默认启动页面;反之跳转到登录页面。
/// </remarks>
public static class SwaggerAuthorizeExtensions
{
public static IApplicationBuilder UseSwaggerAuthorized(this IApplicationBuilder builder)
{
return builder.UseMiddleware<SwaggerAuthMiddleware>();
}
}
}
2.3 重构Program类
//必须在把下面的1行定义上否则会出现异常:““An exception was thrown while activating Microsoft.AspNetCore.Session.DistributedSessionStore.”“An exception was thrown while activating Microsoft.AspNetCore.Session.DistributedSessionStore.””。
builder.Services.AddDistributedMemoryCache();
//把“Session”中间件实例,依赖注入到.Net(Core)7框架内置容器中。
builder.Services.AddSession();
builder.Services.AddControllers();
app.UseMiddleware<CorsMiddleware>();
app.UseSession();
//把自定义“Swagger”授权管道中间件集成到.Net7框架内置管道中,以实现,如果已经被授权则直接访问默认启动页面;反之跳转到登录页面。
app.UseSwaggerAuthorized();
//把自定义“UseSwagger”和“UseSwaggerUI”管道中间件集成到.Net7框架内置管道中,为自定义“index.html”页面渲染显示api提供支撑。
app.UseSwaggerMiddle(() => Assembly.GetExecutingAssembly().GetManifestResourceStream("WebApi.index.html"));
//设定“wwwroot”目录中的“index.html”页面,为默认启动页。
DefaultFilesOptions defaultFilesOptions = new DefaultFilesOptions();
defaultFilesOptions.DefaultFileNames.Clear();
// 说明:该“index.html”页面即不是根目录中的“index.html”页面;也不是“Swagger”中间件内置的“index.html”页面,它是“wwwroot”目录中的“index.html”页面。
//实际上原程序是以根目录中的“index.html”页面,为默认启动页,为了简化定义实现本从并没有复制“wwwroot”目录中的“index.html”页面。
defaultFilesOptions.DefaultFileNames.Add("index.html");
app.UseDefaultFiles(defaultFilesOptions);
app.UseStaticFiles();
按F5执行程序如下图所示:
对以上功能更为具体实现和注释见:221201_07Blog(自定义SwaggerIndex页与登录页)。