记录YiShaAdmin webAPI站点添加身份认证功能。
从Github 下载下来代码发现API身份认证功能貌似没有写完,所以补充这个功能。
没有身份认证时,不用输入token 可以任意调用api接口,显然不符合常理。
接下来进行改造,三步走:
- 设置Authorization header
- 修改AuthorizeFilterAttribute
- API接口授权
具体如下:
- 设置Authorization header
StartUp.cs文件ConfigureServices方法增加如下代码
#region Auth
//Bearer 的scheme定义
var securityScheme = new OpenApiSecurityScheme()
{
Description = "JWT Authorization header using the scheme. Example: \"Authorization: {token}\"",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Scheme = "",
BearerFormat = "JWT"
};
var securityRequirement = new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "token"
}
},
new string[] {}
}
};
#endregion
修改Swagger注入
services.AddSwaggerGen(options =>
{
var xmlPath = Path.Combine(AppContext.BaseDirectory, $"{Assembly.GetExecutingAssembly().GetName().Name}.xml");
options.SwaggerDoc("v1", new OpenApiInfo { Title = "YiSha Api", Version = "v1" });
options.IncludeXmlComments(xmlPath, true);
options.AddSecurityDefinition("token", securityScheme);
options.AddSecurityRequirement(securityRequirement);
});
重新运行项目会发现Authorize在Swagger上已生效
2. 修改AuthorizeFilterAttribute
AuthorizeFilterAttribute.cs文件添加如下代码
private static readonly MenuAuthorizeBLL menuAuthorizeBLL = new MenuAuthorizeBLL();
private static readonly MenuBLL menuBLL = new MenuBLL();
OnActionExecutionAsync方法在sw.Start();和sw.Stop();间修改代码如下:
ActionExecutedContext resultContext = null;
string token = context.HttpContext.Request.Headers["Authorization"].ParseToString();
var actionName = context.ActionDescriptor.RouteValues["action"];
OperatorInfo user = await Operator.Instance.Current(token);
if (user != null)
{
#region 验证权限
var temp = await menuAuthorizeBLL.GetAuthorizeList(user);
// 获取当前请求的URL
var url = context.HttpContext.Request.Path.ToString();
var menu = menuBLL.GetEntity(url);
if (menu != null && menu.Result.Data != null)
{
var menuid = menu.Result.Data.Id;
var t = temp.Data.Where(w => w.MenuId == menuid).Any();
if (t)
{
//有授权
}
else
{
//未授权
//context.HttpContext.Response.StatusCode = 401;
TData obj = new TData();
obj.Tag = 0;
obj.Message = "抱歉,您没有权限";
context.Result = new JsonResult(obj);
return;
}
}
else
{
//未授权
//context.HttpContext.Response.StatusCode = 401;
TData obj = new TData();
obj.Tag = 0;
obj.Message = "抱歉,您没有权限";
context.Result = new JsonResult(obj);
return;
}
#endregion
resultContext = await next();
// 根据传入的Token,设置CustomerId
if (context.ActionArguments != null && context.ActionArguments.Count > 0)
{
PropertyInfo property = context.ActionArguments.FirstOrDefault().Value.GetType().GetProperty("Token");
if (property != null)
{
property.SetValue(context.ActionArguments.FirstOrDefault().Value, token, null);
}
switch (context.HttpContext.Request.Method.ToUpper())
{
case "GET":
break;
case "POST":
property = context.ActionArguments.FirstOrDefault().Value.GetType().GetProperty("CustomerId");
if (property != null)
{
property.SetValue(context.ActionArguments.FirstOrDefault().Value, user.UserId, null);
}
break;
}
}
}
else
{
if (IgnoreToken.Contains(actionName))
{
resultContext = await next();
}
else
{
context.HttpContext.Response.StatusCode = 401;
return;
}
}
验证一下直接请求接口,返回401 符合预期
设置token后,再请求看看
返回没有权限,接下来看看如何授权
3. API接口授权
在菜单中添加API请求URL,然后授权该菜单到需要的角色,当用户的token请求时会解析当前token所属用户属于哪个角色,以及这个角色可访问哪些菜单,在AuthorizeFilter中检测当前请求的Url是否在该用户可访问的菜单中来验证用户是否有调用该API的权限
添加菜单
API授权给角色
再次请求接口,发现已可以正常请求到数据
最后,优化下授权页面
新增菜单类型"API",菜单列表页添加API类型图标显示,如下图
菜单“API清单”设置禁用状态,这样避免在左侧显示API链接。
至此,所有功能设置完毕。