.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
{
...
}

参考

开源地址

.NET Core 反射获取所有控制器及方法上特定标签的更多相关文章

  1. java通过反射获取调用变量以及方法

    一:反射概念 可以通过Class类获取某个类的成员变量以及方法,并且调用之. 二:通过反射获取方法.变量.构造方法 @Test // 通过反射获取类定义的方法 public void testMeth ...

  2. 2019-4-16-C#-使用反射获取私有属性的方法

    title author date CreateTime categories C# 使用反射获取私有属性的方法 lindexi 2019-4-16 10:13:3 +0800 2018-09-26 ...

  3. C#通过反射获取类中的方法和参数个数,反射调用方法带参数

    using System; using System.Reflection; namespace ConsoleApp2 { class Program { static void Main(stri ...

  4. C# 使用反射获取私有属性的方法

    本文告诉大家多个不同的方法使用反射获得私有属性,最后通过测试性能发现所有的方法的性能都差不多 在开始之前先添加一个测试的类 public class Foo { private string F { ...

  5. 第五课 JAVA反射获取对象属性和方法(通过配置文件)

    Service1.java package reflection; public class Service1 { public void doService1(){ System.out.print ...

  6. 第五课 JAVA反射获取对象属性和方法

    package com.hero; import java.lang.reflect.Field; public class TestReflction5 { public static void m ...

  7. .NET/C# 反射的的性能数据,以及高性能开发建议(反射获取 Attribute 和反射调用方法)——转载

    原文链接:https://blog.walterlv.com/post/dotnet-high-performance-reflection-suggestions.html ***** 大家都说反射 ...

  8. 原 .NET/C# 反射的的性能数据,以及高性能开发建议(反射获取 Attribute 和反射调用方法)

    大家都说反射耗性能,但是到底有多耗性能,哪些反射方法更耗性能:这些问题却没有统一的描述. 本文将用数据说明反射各个方法和替代方法的性能差异,并提供一些反射代码的编写建议.为了解决反射的性能问题,你可以 ...

  9. Java反射学习-3 - 反射获取属性,方法,构造器

    package cn.tx.reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import ...

随机推荐

  1. C++ 重载运算符 继承 多态 (超详细)

    (一)重载运算符: (1)声明与定义格式 一般是类内声明,类外定义,虽然可以在类内定义,但 写前面堆一堆不好看!!! 类内声明: class Demo { 返回值类型 operator 运算符(形参表 ...

  2. Python网络数据采集- 创建爬虫

    1. 初见网络爬虫 1.1 网络连接 输出某个网页的全部 HTML 代码. urllib 是 Python 的标准库(就是说你不用额外安装就可以运行这个例子),包含了从网络请求数据,处理 cookie ...

  3. 「从零单排HBase 09」Hbase的那些数据结构和算法

    在之前学习MySQL的时候,我们知道存储引擎常用的索引结构有B+树索引和哈希索引. 而对HBase的学习,也离不开索引结构的学习,它使用了一种LSM树((Log-Structured Merge-Tr ...

  4. B - Save the problem! CodeForces - 867B 构造题

    B - Save the problem! CodeForces - 867B 这个题目还是很简单的,很明显是一个构造题,但是早训的时候脑子有点糊涂,想到了用1 2 来构造, 但是去算这个数的时候算错 ...

  5. js上传文件过大导致上传失败原因以及解决办法

    背景:项目需要用到上传视频功能,由于视频有知识产权,要求必须上传到自己的服务器上不允许用第三方视频网站接口上传,于是一开始开始用的是input type=file去上传,小的视频上传没有问题,上传将近 ...

  6. LeetCode 刷题1---两数之和

    /** 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重复利用这个数组中 ...

  7. 使用EF Code First生成模型,如何让时间字段由数据库自动生成

    场景:保存记录时需要时间字段,该时间如果由前台通过DateTime.Now产生,存在风险,比如修改客户端的系统时间,就会伪造该记录的生成时间.因此,需要在保存记录时,由后台自动赋予具体的时间. 实现方 ...

  8. 软路由OpenWrt(LEDE)2020.4.4编译 UnPnP+NAS+多拨+网盘+DNS优化

    近期更新:2020.04.24编译-基于OpenWrt R2020.3.19版本.   2020.04.04更新记录: 修正国内域名加速脚本部分缺陷 内置打印机共享,ZeroTier 新增多套主题 S ...

  9. 介绍一个船新的 PHP SDK + Runtime: PeachPie

    前言 这几天想基于 .NET Core 搞一个自己的博客网站,于是在网上搜刮各种博客引擎,找到了这些候选:Blogifier.Miniblog 以及 edi 写的 Moonglate. Blogifi ...

  10. [hdu5445 Food Problem]多重背包

    题意:一堆食物,有价值.空间.数量三种属性,一些卡车,有空间,价格,数量三种属性.求最少的钱(不超过50000)买卡车装下价值大于等于给定价值的食物,食物可以拆开来放. 思路:这题的关键是给定的条件: ...