最近在作系统权限这一块,第一次发文记录分享一下,不足之处还请多多指教css
如今咱们作的Web系统,基本都须要权限管理,一是方便用户管理:不一样用户展现不一样的功能菜单;二是方便咱们维护:有些菜单是系统管理员操做的.html
前端校验只是为了提高用户体验,并不能真正的拦截请求 前端
session/token
,而后存储在前端storage
中菜单基本json
结构以下:redis
{
name:'权限中心',
permissionCode:"permission",
isButton:false,
children:[
{
name:'角色管理',
permissionCode:'role',
isButton:false,
children:[
{
name:'角色添加',
permissionCode:'role-add',
isButton:true
},
...
]
}
]
}
复制代码
直接就能够过滤掉没有权限的菜单列表,较为简单json
<ul>
<li v-for="menu in menus">
<a @click="addPage(menu)">{{menu.name}}</a>
</li>
</ul>
复制代码
首先肯定好页面元素的属性规则后端
如给须要权限校验的元素添加一个自定义属性permission
,属性值赋予规定的权限编码
浏览器
//角色页面
<button @click="addRole" permission="role-add">添加</button>
复制代码
删除掉没有权限的元素(按钮、Tab...)安全
permission.js
bash
//1.获取到当前页面权限的元素集合 permissionElements
//2.进行权限检查,将没有权限的元素直接给移除掉
function checkPermission(){
$("[permission]").each(function(ele){
var permissionCode = ele.getAttribute('permission');
if(!permissionElements.first("this.permissionCode=="+permissionCode)){
item.parentNode.removeChild(item);
}
})
}
//体验好一点,能够添加一个css,先将页面须要权限校验的元素给隐藏起来
[permission] { display:none; }
//校验完毕后再显示出来
$("[permission]").each...
.css('display','inline-block')
//每次进入页面就调用了一次,进行权限检查
复制代码
如上
jq
为主的项目,若是总体使用Vue
框架来写会方便许多了session
到这里,前端的权限基本完成了,用户能够看到不一样的菜单和按钮了。
这里算完成了权限吗,能够提升系统安全性吗
普通用户虽然看不到角色菜单列表了,可是在浏览器地址栏输入/role/index.html
仍是同样进入了角色页面,仍是能够看到数据,进行各类操做
真正的作到安全,必须得服务端校验,前面提到了前端的权限校验仅仅是为了提高用户体验
后端使用
.net core
&redis
完成权限的管理,这里作基本代码展现
咱们获取到的菜单是树形结构,这里我把全部的菜单权限编码抽取出来放在一个集合里面,这样校验的时候取值就很容易了
这里使用Redis
的set
数据结构存储,避免权限编码重复
var menuList = GetMenus();
string permissionKey = $"user:{CurrentUser.Id}:permissions";
RedisHelper.SAdd(permissionKey,menuList.Select(m => m.PermissionCode).ToArray());
复制代码
public class PermissionAttribute : Attribute
{
public string PermissionCode { get; set; }
public PermissionAttribute(string permissionCode)
{
PermissionCode = permissionCode;
}
}
复制代码
Api
上添加特性[HttpGet]
[Route("role/add")]
[Permission("role-add")]
public ResponseBase AddRole(){
...
}
复制代码
Filter
,验证全部请求public class MyAuthFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
...其余校验
#region 权限校验
var isCheckPermission = controllerActionDescriptor.MethodInfo.GetCustomAttributes(true)
.Any(a => a.GetType().Equals(typeof(PermissionAttribute)));
if (isCheckPermission)
{
var permissionAttribute = controllerActionDescriptor.MethodInfo.CustomAttributes
.FirstOrDefault(c => c.AttributeType == typeof(PermissionAttribute));
if (permissionAttribute != null)
{
string permissionCode = permissionAttribute.ConstructorArguments[0].Value.ToString();
string[] codes = RedisHelper.SMembers($"user:{User.Id}:permissions");
if (!codes.Contains(permissionCode))
{
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
//需验证tokne是否过时
context.Result = new JsonResult("403没有权限访问资源");
}
}
}
#endregion
}
}
复制代码
到这里基本已经完成啦,权限校验不经过,Http状态码会返回403
,前端再根据状态码去作相应处理就行了.
若是有更好的处理方式,还请教我一下,谢谢