(业精于勤荒于嬉,_ _ _ _ _ _ _)
大家周末好,前两天有个小伙伴在社区里咨询了一个小问题,如何给Swagger页面增加权限,虽然每个接口都已经有了权限,但是还是不想要所有人都能看到接口列表。如果大家没有考虑过这个问题,可以先暂停下,不往下看,喝杯水,思考下如果是自己的话会怎么设计这个需求:
1、过程不要很复杂,但是又可以自由的扩展(下文会说到); 2、重要的一点就是不能对当前项目过多的影响和侵入
我简单的设计了一个方案,可能不是最优解,如果小伙伴有不同的意见,或者更好的建议,欢迎留言哟。废话不多说,马上上代码。
PS:Blog.Core线上已经集成了这个方案,可以自行访问下试试。
地址:http://apk.neters.club/
01PART
自定义Swagger权限拦截中间件
很简单,既然要对Swagger的.html页面进行限制,常规的思路都是增加一个拦截器之类的,那自然而然的就想到了ASP.NetCore的中间件,目前Blog.Core已经集成了16个中间件,涵盖了平时开发需要用到的服务列表、本地Mock用户、异常、限流、审计、权限、MiniProfiler、种子数据、任务调度、Swagger等等,感兴趣的可以一一拆分出来看看学习。
直接上代码:
namespace Blog.Core.Middlewares
{
public class SwaggerAuthMildd
{
private readonly RequestDelegate next;
public SwaggerAuthMildd(RequestDelegate next)
{
this.next = next;
}
public async Task InvokeAsync(HttpContext context)
{
// 也可以根据是否是本地做判断 IsLocalRequest
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);
}
}
public bool IsAuthorized(HttpContext context)
{
// 使用session模式
// 可以使用其他的
return context.Session.GetString("swagger-code") == "success";
}
/// <summary>
/// 判断是不是本地访问
/// 本地不用swagger拦截
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
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;
}
}
// 定义扩展
public static class SwaggerAuthorizeExtensions
{
public static IApplicationBuilder UseSwaggerAuthorized(this IApplicationBuilder builder)
{
return builder.UseMiddleware<SwaggerAuthMildd>();
}
}
}
代码比较简单,主要是拦截了下index.html,因为我是自定义的Swagger首页,如果你有不同的设计,可以酌情修改代码。
此外权限判断的依据,我是用的Session作为当前登录依据,如果存在Session,证明通过,否则跳转到Swagger的登录页,如果浏览器关闭或者换了其他地方Session失效的话,就需要重新登陆,这当然无伤大雅,只要保证浏览器不关闭,其实一直调试是没问题的。
然后就在Startup的中间件管理里,增加上刚刚定义好的中间件扩展方法就行了,而且用到了Session,就需要配置下session的服务注入和中间件:
// 注册服务
services.AddSession();
// 使用中间件,放到Swagger中间件之前
app.UseSession();
app.UseSwaggerAuthorized();
02PART
Swagger登录页设计
上边咱们配置好了中间件,现在就需要配置下无权限的时候的跳转页面了,直接在wwwroot文件夹里新建一个swg-login.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>默认首页</title>
<script src="http://code.jquery.com/jquery-1.8.3.min.js"></script>
</head>
<body>
<div id="requestMsg"></div>
<div style="text-align: center;">
<p>用户名:admin,密码:admin</p>
<input id="name" placeholder="name" type="text" />
<br />
<input id="pwd" placeholder="pwd" type="password" />
<br />
<input type="submit" onclick="submit()" value="submit" />
</div>
<script>
function submit() {
let postdata = {
"name": $("#name").val(),
"pwd": $("#pwd").val(),
};
if (!(postdata.name && postdata.pwd)) {
alert('参数不正确');
return
}
$.ajax({
url: "/api/Login/swgLogin",
type: "POST",
contentType: "application/json; charset=utf-8",
data: JSON.stringify(postdata),
dataType: 'json',
success: function (data) {
if (data?.result) {
window.location.href = "/index.html";
} else {
alert('参数不正确');
}
}
});
}
</script>
</body>
</html>
代码很简单,就是做一个Ajax的Post请求,成功后跳转到Swagger的index页面即可。
03PART
Swagger的登录接口
这一块就更简单了,直接接收用户名和密码就行,然后存到Session里,其实这一块的扩展性很强,无论是简单的登录,还是连接数据的登录都是可以的:
/// <summary>
/// swagger登录
/// </summary>
/// <param name="loginRequest"></param>
/// <returns></returns>
[HttpPost]
[Route("swgLogin")]
public dynamic SwgLogin([FromBody] SwaggerLoginRequest loginRequest)
{
// 这里可以查询数据库等各种校验
if (loginRequest?.name == "admin" && loginRequest?.pwd == "admin")
{
HttpContext.Session.SetString("swagger-code", "success");
return new { result = true };
}
return new { result = false };
}
到这里基本都已经完成了,很简单的过程,来个效果动图看看吧
04PART
其他说明
其实本文只是众多思路当中的一个,你可以发散思维,比如直接在我们的Swagger自定义的首页里做操作,毕竟是自定义的index.html嘛,可以加个登录。
也可以使用我这种单独登录页面的方案,再丰富些,对接ids4认证中心等等,都是不错的想法和思路。
好啦,今天就到这里了,欢迎更多的小伙伴来分享更好更棒的思路吧。
本文分享自 NetCore 从壹开始 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!