.NET Core 反射獲取所有控制器及方法上特定標簽


.NET Core 反射獲取所有控制器及方法上特定標簽

有個需求,就是在. 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
{
    ...
}

參考

開源地址


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM