1.以前我們的權限主要靠手工錄入到系統中,然後進行驗證,這種方式不僅耗時,而且一旦按鈕id 發生變動等情況 維護比較麻煩,現在我們采用直接從Controller中讀取對應的action 進行設定權限,這樣就不需要做過多元護以下是源碼
/// <summary>
/// 控制器操作類
/// </summary>
public class ControllerHelper
{
private const string All_ControllerActionCacheKey = "All_System_ControllerHelper_Actions_List";
/// <summary>
/// 擷取所有頁面的Action
/// </summary>
public static List<BasePermissionAttribute> AuthAttributes
{
get
{
return ApplicationEnvironments.CacheService.Get<List<BasePermissionAttribute>>(All_ControllerActionCacheKey, () =>
{
return new ControllerHelper().GetAllActions();
}, true);
}
}
/// <summary>
/// 擷取單頁面的Action
/// </summary>
/// <param name="areaName"></param>
/// <param name="controllerName"></param>
/// <returns></returns>
public static List<BasePermissionAttribute> GetActionsByPage(string areaName,string controllerName) {
if (AuthAttributes != null && AuthAttributes.Count > 0)
{
return AuthAttributes.Where(x=>x.AreaName.ToLower().Equals(areaName.ToLower())&&x.ControllerName.ToLower().Equals(controllerName.ToLower())).ToList();
}
return null;
}
/// <summary>
/// 擷取所有頁面的Action
/// </summary>
private List<BasePermissionAttribute> GetAllActions()
{
#region 通過反射讀取Action方法寫入對應權限至集合
List<BasePermissionAttribute> authAttributes = new List<BasePermissionAttribute>();
//讀取目前項目程式集中內建自AdminController的控制器
var files = System.IO.Directory.GetFiles(AppContext.BaseDirectory, "*.Web.dll");
if (files != null && files.Length > 0)
{
foreach (var file in files)
{
var assembly = Assembly.LoadFrom(file);
var types = assembly.GetTypes().Where(x => x.IsSubclassOf(typeof(BaseController))).ToList();
//var now = DateTime.Now;
foreach (var type in types)
{
//擷取所有action方法
GetControllerActions(type,ref authAttributes);
}
}
}
return authAttributes;
#endregion
}
/// <summary>
/// 擷取單個控制器中的Actions
/// </summary>
/// <param name="controller"></param>
private void GetControllerActions(Type controller, ref List<BasePermissionAttribute> authAttributes)
{
var areaAttr= controller.GetCustomAttribute(typeof(AreaAttribute),true);
string areaName = "";
if (areaAttr != null)
{
areaName = (areaAttr as AreaAttribute).RouteValue;
}
var members = controller.GetMethods().Where(e => e.ReturnType.Name == nameof(ActionResult)
|| e.ReturnType.Name == nameof(IActionResult)
|| e.ReturnType.Name == nameof(JsonResult)
);
string[] systemAction = {"index","forgrid" };
foreach (var member in members)
{
if (systemAction.Contains(member.Name.ToLower()))
{
continue;
}
//擷取功能清單
var attr = member.GetCustomAttribute(typeof(BasePermissionAttribute), true) ;
if (attr == null)
continue;
var auth = attr as BasePermissionAttribute;
if (string.IsNullOrWhiteSpace(auth.ActionCode)|| !string.IsNullOrWhiteSpace(auth.ActionName) || auth.IsParent|| auth.NoAccess)
{
continue;
}
auth.AreaName = areaName;
if (string.IsNullOrWhiteSpace(auth.ActionName))
{
auth.ActionName = member.Name;
}
auth.ControllerName = controller.Name.Replace("Controller", "");
//功能對應的二級菜單
authAttributes.Add(auth);
}
}
}
2.BasePermissionAttribute權限基類,
主要用于定義action 通路屬性,由于在底層需要引用該類友善存儲讀取controller中的action 是以需要這個基類,如果項目這個類放在業務層是不需要分開的
public class BasePermissionAttribute :Attribute, IAsyncAuthorizationFilter
{
/// <summary>
/// get請求是否需要驗證權限 預設是
/// </summary>
public bool IsGet { get; set; }
/// <summary>
/// post請求是否需要驗證權限 預設是
/// </summary>
public bool IsPost { get; set; }
/// <summary>
/// 描述
/// </summary>
public string Description { get; set; }
/// <summary>
/// 與其它ActionName權限一樣
/// </summary>
public string ActionCode { get; set; }
/// <summary>
/// Action名稱
/// </summary>
public string ActionName { get; set; }
/// <summary>
/// 域名稱
/// </summary>
public string AreaName { get; set; }
/// <summary>
/// 控制器名稱
/// </summary>
public string ControllerName { get; set; }
/// <summary>
/// 是否繼承controller Index通路權限
/// </summary>
public bool IsParent { get; set; }
/// <summary>
/// 不允許通路
/// </summary>
public bool NoAccess { get; set; }
//public PermissionAttribute()
//{
// IsGet = true;
// IsPost = true;
//}
public BasePermissionAttribute() {
IsGet = true;
IsPost = true;
IsParent = false;
}
public BasePermissionAttribute(string code,string description)
{
IsGet = true;
IsPost = true;
IsParent = false;
ActionCode = "BTN" + code;
Description = description;
}
/// <summary>
/// 輸出錯誤資訊
/// </summary>
/// <param name="filterContext"></param>
/// <param name="strError"></param>
public void WriteResult(AuthorizationFilterContext filterContext, string strError)
{
var areaName = "";
var actionName = filterContext.RouteData.Values["Action"].ToString();
var controllerName = filterContext.RouteData.Values["controller"].ToString();
if (filterContext.RouteData.DataTokens["area"] != null)
{
areaName = filterContext.RouteData.DataTokens["area"].ToString();
}
//new LogErrorService().Save((!string.IsNullOrEmpty(areaName)?areaName+"/"+controllerName:controllerName),actionName,strError,strError);
if (AppHttpContext.IsPost&&AppHttpContext.IsAjax)
{
filterContext.HttpContext.Response.StatusCode = 200;
filterContext.Result = new JsonResult(AjaxResult.Error(strError, -100));
}
else
{
var view = new ViewResult();
view.ViewName = "~/Views/Home/Error.cshtml";
view.ViewData = new Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary(new BaseController().ViewData);
view.ViewData["Message"] = strError;
view.ViewData["Exception"] = new Exception(strError);
filterContext.Result = view;
}
}
public virtual Task OnAuthorizationAsync(AuthorizationFilterContext filterContext)
{
return Task.CompletedTask;
}
3.權限的具體實作
public class PermissionAttribute : BasePermissionAttribute
{
public PermissionAttribute():base()
{
}
/// <summary>
///
/// </summary>
/// <param name="code">權限辨別(controller中請勿重複)</param>
/// <param name="description">描述</param>
public PermissionAttribute(string actionCode, string description) : base(actionCode, description)
{
}
public override Task OnAuthorizationAsync(AuthorizationFilterContext filterContext)
{
//匿名辨別 無需驗證
if (filterContext.Filters.Any(e => (e as AllowAnonymousAttribute) != null))
return Task.CompletedTask;
if ((AppHttpContext.IsPost && !IsPost)||(!AppHttpContext.IsPost && !IsGet))
{
return Task.CompletedTask;
}
if (NoAccess)
{
WriteResult(filterContext, "該接口不允許通路");
return Task.CompletedTask;
}
if (!AppHttpContext.Current.User.Identity.IsAuthenticated)
{
WriteResult(filterContext, "未登入,無權通路");
return Task.CompletedTask;
}
var userEntity = ApplicationEnvironments.DefaultSession.GetUser<UserEntity>();
if (userEntity == null)
{
WriteResult(filterContext, "對不起,您無權通路");
return Task.CompletedTask;
}
//擷取請求的區域,控制器,action名稱
this.AreaName = string.IsNullOrWhiteSpace(this.AreaName) ? filterContext.RouteData.Values["area"]?.ToString() : this.AreaName;
this.ControllerName = string.IsNullOrWhiteSpace(this.ControllerName) ? filterContext.RouteData.Values["controller"]?.ToString() : this.ControllerName;
this.ActionName = string.IsNullOrWhiteSpace(this.ActionName) ? filterContext.RouteData.Values["action"]?.ToString() : this.ActionName;
if (IsParent)
{
this.ActionName = "Index";
}
var isPermit = false;
if (string.IsNullOrWhiteSpace(ControllerName) || ControllerName.ToLower().Equals("home"))
{
ControllerName = "";
}
if (string.IsNullOrWhiteSpace(ActionName) || ActionName.ToLower().Equals("index"))
{
ActionName = "";
}
string routeUrl = "";
routeUrl = (!string.IsNullOrWhiteSpace(AreaName) ? AreaName + "/" : "").ToLower();
if(!string.IsNullOrWhiteSpace(ControllerName))
{
routeUrl += ControllerName.ToLower() + (!string.IsNullOrWhiteSpace(ActionName) ? "/" : "");
}
routeUrl += ActionName.ToLower();
var isUmPermit = userEntity.UnPermission.Where(x => x.RouteUrl.ToLower().Equals(routeUrl)).FirstOrDefault() != null;
if (!isUmPermit)
{
isPermit = userEntity.Permission.Where(x => x.RouteUrl.ToLower().Equals(routeUrl)).FirstOrDefault() != null;
if (isPermit)
{
return Task.CompletedTask;
}
}
WriteResult(filterContext, "對不起,您無權通路");
return Task.CompletedTask;
}
}
4.在action 上增加如下代碼 即可
[Permission("Code", "名稱")]
版權聲明:本文為CSDN部落客「weixin_33962621」的原創文章,遵循CC 4.0 BY-SA版權協定,轉載請附上原文出處連結及本聲明。
原文連結:https://blog.csdn.net/weixin_33962621/article/details/92372310