.NET Core reflection retrieves specific tags on all controllers and methods

There is a need, is in. In NET Core, we want to get all the places where the LinCmsAuthorizeAttribute tag appears when the project starts, put its parameters in a collection and cache it so that we can use that data later for permission validation.

We use reflection to get attributes for all controllers and methods.

What is LinCmsAuthorizeAttribute

The code is very simple for custom permission validation, overriding the OnAuthorizationAsync method to allow fixed permissions to be assigned to dynamic roles (and also to dynamic users). This paper mainly studies the implementation of authorization-based authorization and implements the method level authorization verification.

  • www.cnblogs.com/RainingNigh…

Of course, this is only part of the code, complete code please see the bottom open source address, where LinCmsAuthorizeAttribute inherits AuthorizeAttribute, has the specified role Permission control, when Permission is not specified, when the filter and Authorize function is the same. Module refers to a Module, that is, multiple permissions belong to the same Module, which is convenient to display in the foreground as a tree structure. The value of the Permission attribute is non-repeatable.

[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 stringToString()
    {
        return $"\"{base.ToString()}\",\"Permission:{Permission}\",\"Module:{Module}\",\"Roles:{Roles}\",\"Policy:{Policy}\",\"Authentic ationSchemes:{AuthenticationSchemes}\""; }}Copy the code

Controller

As for the Controller in lincms. Web, the main reason why Permission is Chinese is that this project is used for lin-cms-Vue project, so it is different to use a certain string as Permission name, but it does not need to be big and small, the same reason.

[Route("cms/log")]
[ApiController]
public class LogController : ControllerBase
{
    private readonly ILogService _logService;

    public LogController(ILogService logService)
    {
        _logService = logService;
    }

    [HttpGet("users")]
    [LinCmsAuthorize("User who queried log records"."Log")]
    public List<string> GetLoggedUsers([FromQuery]PageDto pageDto)
    {
        return _logService.GetLoggedUsers(pageDto);
    }

 
    [HttpGet]
    [LinCmsAuthorize("Query all Logs"."Log")]
    public PagedResultDto<LinLog> GetLogs([FromQuery]LogSearchDto searchDto)
    {
        return _logService.GetLogUsers(searchDto);
    }

    [HttpGet("search")]
    [LinCmsAuthorize("Search log"."Log")]
    public PagedResultDto<LinLog> SearchLogs([FromQuery]LogSearchDto searchDto)
    {
        return_logService.GetLogUsers(searchDto); }}Copy the code

Test a class to get a specific label on a method

In xunit test project, start our 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()); }}}}); }Copy the code

Methods the results

You can see it in the output text, which is exactly what we want, and the last line, which is from the other Controller, and we overwrote ToString(), so we can see its properties.

"LinCms.Zero.Authorization.LinCmsAuthorizeAttribute"."Permission: user who queries log records"."The Module: log"."Roles:"."Policy:"."AuthenticationSchemes:"
"LinCms.Zero.Authorization.LinCmsAuthorizeAttribute"."Permission: Queries all logs"."The Module: log"."Roles:"."Policy:"."AuthenticationSchemes:"
"LinCms.Zero.Authorization.LinCmsAuthorizeAttribute"."Permission: Search log"."The Module: log"."Roles:"."Policy:"."AuthenticationSchemes:"
"LinCms.Zero.Authorization.LinCmsAuthorizeAttribute"."Permission: View information about Lin"."The Module: information"."Roles:"."Policy:"."AuthenticationSchemes:"

Copy the code

Gets the feature label on the controller

// <summary> /// get the L on the controllerinCmsAuthorizeAttribute
/// </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());
        }
    });
}
Copy the code

Results of the Controller

Only AdminController adds this tag, so there is only one line.

"LinCms.Zero.Authorization.LinCmsAuthorizeAttribute"."Permission:"."Module:"."Roles:Administrator"."Policy:"."AuthenticationSchemes:"
Copy the code

LinGroup =”Administrator”; LinGroup =”Administrator”; LinGroup =”Administrator”; Have to set up a new Claim the current logged in user (ClaimTypes. Role, user IsAdmin ()? LinGroup. Administrator: user. The GroupId. ToString ()), or “Administrator, when a user access method in AdminController, LinCmsAuthorize and didn’t do the related validation, All of them are AuthorizeAttribute, which realizes the judgment of fixed role permissions and login. LinCmsAuthorize Determines whether users have the permissions after setting the fixed permissions to different dynamic roles.

[LinCmsAuthorize(Roles = LinGroup.Administrator)]
public class AdminController : ControllerBase
{
    ...
}
Copy the code

reference

  • Codeday. me/bug/2018120…

Open source address

  • Github.com/luoyunchong…