最近在作系統權限這一塊,第一次發文記錄分享一下,不足之處還請多多指教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
,前端再根據狀態碼去作相應處理就行了.
若是有更好的處理方式,還請教我一下,謝謝