該篇內容由個人博客點擊跳轉同步更新!轉載請注明出處!
獲取控制器及方法特性標簽
有個需求,就是在. NET Core中,我們想在項目 啟動時,獲取LinCmsAuthorizeAttribute這個特性標簽所有出現的地方,把他的參數,放入一個集合并緩存起來,以便后面使用此數據用于權限驗證。
我們通過反射獲取所有控制器下及方法的Attribute。
LinCmsAuthorizeAttribute是什么
其代碼非常簡單,用于自定義權限驗證,通過重寫OnAuthorizationAsync方法,實現固定權限可分配給動態角色(也能分配給動態用戶)。主要就基于權限的授權的實現進行研究,實現方法級別的權限驗證。
當然,這個只是部分代碼,完整代碼請查看最下方開源地址,其中LinCmsAuthorizeAttribute繼承AuthorizeAttribute,擁有指定角色權限控制,當Permission未指定時,當過濾器與Authorize功能相同。Module是指模塊,即多個權限,屬于同一個模塊,方便前臺展示為樹型結構。Permission屬性的值不可重復。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class LinCmsAuthorizeAttribute : AuthorizeAttribute, IAsyncAuthorizationFilter
{
public string Permission { get; set; }
public string Module { get; set; }
public LinCmsAuthorizeAttribute()
{
}
public LinCmsAuthorizeAttribute(string permission,string module)
{
Permission = permission;
Module = module;
}
public LinCmsAuthorizeAttribute(string permission,string module, string policy) : base(policy)
{
Permission = permission;
Module = module;
}
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
if (Permission == null) return;
var authorizationService = (IAuthorizationService)context.HttpContext.RequestServices.GetService(typeof(IAuthorizationService));
var authorizationResult = await authorizationService.AuthorizeAsync(context.HttpContext.User, null, new OperationAuthorizationRequirement() { Name = Permission });
if (!authorizationResult.Succeeded)
{
context.Result = new ForbidResult();
}
}
public override string ToString()
{
return $"\"{base.ToString()}\",\"Permission:{Permission}\",\"Module:{Module}\",\"Roles:{Roles}\",\"Policy:{Policy}\",\"AuthenticationSchemes:{AuthenticationSchemes}\"";
}
}
Controller
在 LinCms.Web中的Controller,至于為什么Permission為中文,目前的主要原因,此項目用于適配 Lin-CMS-VUE項目,所以于平常我們以某個字符串作為權限名不同,但不須大驚小怪,道理相同。
[Route("cms/log")]
[ApiController]
public class LogController : ControllerBase
{
private readonly ILogService _logService;
public LogController(ILogService logService)
{
_logService = logService;
}
[HttpGet("users")]
[LinCmsAuthorize("查詢日志記錄的用戶", "日志")]
public List<string> GetLoggedUsers([FromQuery]PageDto pageDto)
{
return _logService.GetLoggedUsers(pageDto);
}
[HttpGet]
[LinCmsAuthorize("查詢所有日志", "日志")]
public PagedResultDto<LinLog> GetLogs([FromQuery]LogSearchDto searchDto)
{
return _logService.GetLogUsers(searchDto);
}
[HttpGet("search")]
[LinCmsAuthorize("搜索日志", "日志")]
public PagedResultDto<LinLog> SearchLogs([FromQuery]LogSearchDto searchDto)
{
return _logService.GetLogUsers(searchDto);
}
}
測試類獲取方法上的特定標簽
in xunit test 項目工程中,開始我們的測試
[Fact]
public void GetAssemblyMethodsAttributes()
{
var assembly = typeof(Startup).Assembly.GetTypes().AsEnumerable()
.Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToList();
assembly.ForEach(r =>
{
foreach (var methodInfo in r.GetMethods())
{
foreach (Attribute attribute in methodInfo.GetCustomAttributes())
{
if (attribute is LinCmsAuthorizeAttribute linCmsAuthorize)
{
_testOutputHelper.WriteLine(linCmsAuthorize.ToString());
}
}
}
});
}
方法結果
可在輸出文本中查看,正是我們想要的東西,最后一行,是其他Controller中的內容,而且我們重寫了ToString(),所以我們能看到其屬性。
"LinCms.Zero.Authorization.LinCmsAuthorizeAttribute","Permission:查詢日志記錄的用戶","Module:日志","Roles:","Policy:","AuthenticationSchemes:"
"LinCms.Zero.Authorization.LinCmsAuthorizeAttribute","Permission:查詢所有日志","Module:日志","Roles:","Policy:","AuthenticationSchemes:"
"LinCms.Zero.Authorization.LinCmsAuthorizeAttribute","Permission:搜索日志","Module:日志","Roles:","Policy:","AuthenticationSchemes:"
"LinCms.Zero.Authorization.LinCmsAuthorizeAttribute","Permission:查看lin的信息","Module:信息","Roles:","Policy:","AuthenticationSchemes:"
獲取控制器上特性標簽
/// <summary>
/// 獲取控制器上的LinCmsAuthorizeAttribute
/// </summary>
/// "LinCms.Zero.Authorization.LinCmsAuthorizeAttribute","Permission:","Module:","Roles:Administrator","Policy:","AuthenticationSchemes:"
[Fact]
public void GetControllerAttributes()
{
var assembly = typeof(Startup).Assembly.GetTypes().AsEnumerable()
.Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToList();
assembly.ForEach(d =>
{
var linCmsAuthorize = d.GetCustomAttribute<LinCmsAuthorizeAttribute>();
if (linCmsAuthorize != null)
{
_testOutputHelper.WriteLine(linCmsAuthorize.ToString());
}
});
}
Controller結果
只有AdminController加了此標簽,所以只有一行。
"LinCms.Zero.Authorization.LinCmsAuthorizeAttribute","Permission:","Module:","Roles:Administrator","Policy:","AuthenticationSchemes:"
此時Roles為Administrator,Permission及Module都是null,
這是因為只有AdminController中加了LinGroup.Administrator="Administrator"字符串,在登錄過程中,已經給當前登錄用戶設置了 new Claim(ClaimTypes.Role,user.IsAdmin()?LinGroup.Administrator:user.GroupId.ToString()),即"Administrator,當用戶訪問AdminController中的方法時,LinCmsAuthorize并沒有做相關驗證,都是AuthorizeAttribute,實現了固定角色權限的判斷及登錄的判斷。LinCmsAuthorize完成了固定權限設置為不同的動態角色后,判斷用戶是否擁有此權限。
[LinCmsAuthorize(Roles = LinGroup.Administrator)]
public class AdminController : ControllerBase
{
...
}
參考
- c# – 如何在asp. net core rc2中獲取控制器的自定義屬性 https://codeday.me/bug/20181207/453278.html