如何在ASP.NETCore中创建自定义AuthorizeAttribute?

如何在ASP.NETCore中创建自定义AuthorizeAttribute?

2023年6月20日发(作者:)

如何在e中创建⾃定义AuthorizeAttribute?本⽂翻译⾃:I'm trying to make a custom authorization attribute in Core. 我正在尝试在 Core中创建⾃定义授权属性。我正在尝试在 Core中创建⾃定义授权属性。

Inprevious versions it was possible to override

bool AuthorizeCore(HttpContextBase httpContext) . 在以前的版本中,可以重写在以前的版本中,可以重写boolAuthorizeCore(HttpContextBase httpContext) 。 。But this no longer exists in . 但这在不再存在。但这在不再存在。What is the current approach to make a custom AuthorizeAttribute? 制作⾃定义AuthorizeAttribute的当前⽅法是什么?制作⾃定义AuthorizeAttribute的当前⽅法是什么?What I am trying to accomplish: I am receiving a session ID in the Header Authorization. 我要完成的⼯作:我在标题授权中收我要完成的⼯作:我在标题授权中收到⼀个会话ID。 到⼀个会话ID。From that ID I'll know whether a particular action is valid. 通过该ID,我将知道特定操作是否有效。通过该ID,我将知道特定操作是否有效。#1楼#2楼What is the current approach to make a custom AuthorizeAttribute 制作⾃定义AuthorizeAttribute的当前⽅法是什么制作⾃定义AuthorizeAttribute的当前⽅法是什么Easy: don't create your own

AuthorizeAttribute . 简单:不要创建⾃⼰的简单:不要创建⾃⼰的AuthorizeAttribute 。public class Startup{ public void ConfigureServices(IServiceCollection services) { ure(options => { icy("ManageStore", policy => eClaim("Action", "ManageStore")); }); }}

public class StoreController : Controller{ [Authorize(Policy = "ManageStore"), HttpGet] public async Task Manage() { ... }}For authentication, it's best handled at the middleware level. 对于⾝份验证,最好在中间件级别进⾏处理。对于⾝份验证,最好在中间件级别进⾏处理。What are you trying to achieve exactly? 您到底想达到什么⽬标?您到底想达到什么⽬标?#3楼I'm the security person. 我是安全⼈员。我是安全⼈员。

Firstly let me apologize that none of this is documented yet outsideof the music store sample or unit tests, and it's all still being refined in terms of exposed APIs. ⾸先,我很抱歉,除了⾳乐商⾸先,我很抱歉,除了⾳乐商店样本或单元测试之外,没有任何⽂档被记录下来,并且仍然在公开的API⽅⾯对其进⾏了完善。 店样本或单元测试之外,没有任何⽂档被记录下来,并且仍然在公开的API⽅⾯对其进⾏了完善。Detailed documentation is . 详详细的⽂档在 。We don't want you writing custom authorize attributes. 我们不希望您编写⾃定义授权属性。我们不希望您编写⾃定义授权属性。

If you need to do that we've donesomething wrong. 如果您需要这样做,我们做错了。如果您需要这样做,我们做错了。

Instead, you should be writing authorization requirements . 相反,您应该相反,您应该编写授权要求 。Authorization acts upon Identities. 授权作⽤于⾝份。授权作⽤于⾝份。

Identities are created by authentication. ⾝份是通过⾝份验证创建的。⾝份是通过⾝份验证创建的。You say in comments you want to check a session ID in a header. 您在注释中说,您想检查标题中的会话ID。您在注释中说,您想检查标题中的会话ID。

Your session IDwould be the basis for identity. 您的会话ID将成为⾝份的基础。您的会话ID将成为⾝份的基础。

If you wanted to use the

Authorize attribute you'd write anauthentication middleware to take that header and turn it into an authenticated

ClaimsPrincipal . 如果您想使⽤如果您想使⽤Authorize属性,则可以编写⾝份验证中间件来获取该标头并将其转换为经过⾝份验证的ClaimsPrincipal 。 。You would then check that inside anauthorization requirement. 然后,您将在授权要求中进⾏检查。然后,您将在授权要求中进⾏检查。

Authorization requirements can be as complicated as you like,for example here's one that takes a date of birth claim on the current identity and will authorize if the user is over 18; 授权要授权要求可以任意复杂,例如,这⾥要求以当前⾝份声明出⽣⽇期,并在⽤户超过18岁时进⾏授权;8public class Over18Requirement : AuthorizationHandler, IAuthorizationRequirement{ public override void Handle(AuthorizationHandlerContext context, Over18Requirement requirement) { if (!im(c => == Birth)) { (); return; }

var dateOfBirth = Time(rst(c => == Birth).Value); int age = - ; if (dateOfBirth > rs(-age)) { age--; }

if (age >= 18) { d(requirement); } else { (); } } }}Then in your

ConfigureServices() function you'd wire it up 然后在您的然后在您的ConfigureServices()函数中将其连接起来horization(options =>{ icy("Over18",

policy => (new 18Requirement()));});And finally, apply it to a controller or action method with 最后,通过以下⽅式将其应⽤于控制器或操作⽅法最后,通过以下⽅式将其应⽤于控制器或操作⽅法[Authorize(Policy = "Over18")]#4楼You can create your own AuthorizationHandler that will find custom attributes on your Controllers and Actions, and passthem to the HandleRequirementAsync method. 您可以创建⾃⼰的AuthorizationHandler,以在Controllers和Actions上找您可以创建⾃⼰的AuthorizationHandler,以在Controllers和Actions上找到⾃定义属性,并将它们传递给HandleRequirementAsync⽅法。223public abstract class AttributeAuthorizationHandler : AuthorizationHandler where TRequirement : IAuthorizationR{ protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement) { var attributes = new List();

var action = (ce as AuthorizationFilterContext)?.ActionDescriptor as ControllerActionDescriptor; if (action != null) { ge(GetAttributes(yingSystemType)); ge(GetAttributes(Info)); }

return HandleRequirementAsync(context, requirement, attributes); }

protected abstract Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement, IEnumerable attributes

private static IEnumerable GetAttributes(MemberInfo memberInfo) { return tomAttributes(typeof(TAttribute), false).Cast(); }}Then you can use it for any custom attributes you need on your controllers or actions. 然后,您可以将其⽤于控制然后,您可以将其⽤于控制器或操作上器或操作上所需的任何⾃定义属性。 所需的任何⾃定义属性。For example to add permission requirements. 例如添加权限要求。例如添加权限要求。

Just create your customattribute. 只需创建您的⾃定义属性。只需创建您的⾃定义属性。[AttributeUsage( | , AllowMultiple = true)]public class PermissionAttribute : AuthorizeAttribute{ public string Name { get; }

public PermissionAttribute(string name) : base("Permission") { Name = name; }}Then create a Requirement to add to your Policy 然后创建⼀个要求以添加到您的策略中然后创建⼀个要求以添加到您的策略中1234public class PermissionAuthorizationRequirement : IAuthorizationRequirement{ //Add any custom requirement properties if you have them}Then create the AuthorizationHandler for your custom attribute, inheriting the AttributeAuthorizationHandler that wecreated earlier. 然后,为您的⾃定义属性创建AuthorizationHandler,并继承我们先前创建的然后,为您的⾃定义属性创建AuthorizationHandler,并继承我们先前创建的AttributeAuthorizationHandler。 AttributeAuthorizationHandler。It will be passed an IEnumerable for all your custom attributes in theHandleRequirementsAsync method, accumulated from your Controller and Action. 将为HandleRequirementsAsync⽅法中将为HandleRequirementsAsync⽅法中的所有⾃定义属性传递⼀个IEnumerable,该IEnumerable是从Controller和Action累积的。17181920public class PermissionAuthorizationHandler : AttributeAuthorizationHandler{ { foreach (var permissionAttribute in attributes) { if (!await AuthorizeAsync(, )) { return; } }

d(requirement); }

private Task AuthorizeAsync(ClaimsPrincipal user, string permission) { //Implement your custom user permission logic here }} protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionAuthorizationRequirement requirement, IEnumAnd finally, in your ConfigureServices method, add your custom AuthorizationHandler to the services, and addyour Policy. 最后,在 ConfigureServices⽅法中,将⾃定义AuthorizationHandler添加到服务中,然后添加最后,在 ConfigureServices⽅法中,将⾃定义AuthorizationHandler添加到服务中,然后添加Policy。123456789 gleton();

horization(options => { icy("Permission", policyBuilder => { (new PermissionAuthorizationRequirement()); }); });Now you can simply decorate your Controllers and Actions with your custom attribute. 现在,您可以使⽤⾃定义属性简单地装现在,您可以使⽤⾃定义属性简单地装饰控制器和动作。123456789[Permission("AccessCustomers")]public class CustomersController{ [Permission("AddCustomer")] IActionResult AddCustomer([FromBody] Customer customer) { //Add customer }}#5楼The approach recommended by the Core team is to use the new policy design which is fully documented . e团队推荐的⽅法是使⽤新的策略设计, 其详细记录。 Core团队推荐的⽅法是使⽤新的策略设计, 其详细记录。The basic idea behind the new approach is to use the new[Authorize] attribute to designate a "policy" (eg

[Authorize( Policy = "YouNeedToBe18ToDoThis")] where the policy is registeredin the application's to execute some block of code (ie ensure the user has an age claim where the age is 18 orolder). 新⽅法的基本思想是使⽤新的[Authorize]属性来指定⼀个“策略”(例如新⽅法的基本思想是使⽤新的[Authorize]属性来指定⼀个“策略”(例如[Authorize( Policy ="YouNeedToBe18ToDoThis")] ,该策略已在应⽤程序的中注册以执⾏某些代码(即确保⽤户具有18岁或18岁以上的年龄声明)。The policy design is a great addition to the framework and the Security Core team should be commended for itsintroduction. 策略设计是对框架的重要补充, Security Core团队的引⼊值得赞扬。策略设计是对框架的重要补充, Security Core团队的引⼊值得赞扬。

That said, it isn't well-suited forall cases. 也就是说,它并不适合所有情况。也就是说,它并不适合所有情况。

The shortcoming of this approach is that it fails to provide a convenient solutionfor the most common need of simply asserting that a given controller or action requires a given claim type. 这种⽅法的缺点这种⽅法的缺点在于,它⽆法为最简单的要求简单断⾔给定的控制器或操作需要给定的索赔类型的最常见需求提供⽅便的解决⽅案。 在于,它⽆法为最简单的要求简单断⾔给定的控制器或操作需要给定的索赔类型的最常见需求提供⽅便的解决⽅案。In the casewhere an application may have hundreds of discrete permissions governing CRUD operations on individual REST resources("CanCreateOrder", "CanReadOrder", "CanUpdateOrder", "CanDeleteOrder", etc.), the new approach either requires repetitiveone-to-one mappings between a policy name and a claim name (eg

icy("CanUpdateOrder", policy =>eClaim(sion, "CanUpdateOrder)); ), or writing some code to perform these registrations at runtime (eg read all claim types from a database and perform the aforementioned call in a loop). The problem with thisapproach for the majority of cases is that it's unnecessary overhead. 如果应⽤程序可能具有数百个离散权限来管理单个REST如果应⽤程序可能具有数百个离散权限来管理单个REST资源(“ CanCreateOrder”,“ CanReadOrder”,“ CanUpdateOrder”,“ CanDeleteOrder”等)上的CRUD操作,则新⽅法要么需要重复的⼀对⼀操作,要么⼀种策略名称与声明名称之间的映射(例如icy("CanUpdateOrder",policy => eClaim(sion, "CanUpdateOrder)); ),或编写⼀些代码以在运⾏时执⾏这些注册(例如,从数据库中读取所有索赔类型,然后循环执⾏上述调⽤。)在⼤多数情况下,这种⽅法的问题是不必要的开销。While the Core Security team recommends never creating your own solution, in some cases this may be the mostprudent option with which to start. 尽管 Core Security团队建议不要创建⾃⼰的解决⽅案,但在某些情况下,这可能尽管 Core Security团队建议不要创建⾃⼰的解决⽅案,但在某些情况下,这可能是最明智的选择。The following is an implementation which uses the IAuthorizationFilter to provide a simple way to express a claimrequirement for a given controller or action: 以下是使⽤IAuthorizationFilter的实现,以提供⼀种简单的⽅式来表达给定控制器以下是使⽤IAuthorizationFilter的实现,以提供⼀种简单的⽅式来表达给定控制器或操作的声明要求:829363738public class ClaimRequirementAttribute : TypeFilterAttribute{ public ClaimRequirementAttribute(string claimType, string claimValue) : base(typeof(ClaimRequirementFilter)) { Arguments = new object[] {new Claim(claimType, claimValue) }; }}

public class ClaimRequirementFilter : IAuthorizationFilter{ readonly Claim _claim;

public ClaimRequirementFilter(Claim claim) { _claim = claim; }

public void OnAuthorization(AuthorizationFilterContext context) { var hasClaim = (c => == _ && == _); if (!hasClaim) { = new ForbidResult(); } }}

[Route("api/resource")]public class MyController : Controller{ [ClaimRequirement(sion, "CanReadResource")] [HttpGet] public IActionResult GetResource() { return Ok(); }}#6楼Based on Derek Greer GREAT answer, i did it with enums. 基于Derek Greer GREAT的答案,我使⽤枚举来做到这⼀点。基于Derek Greer GREAT的答案,我使⽤枚举来做到这⼀点。Here is an example of my code: 这是我的代码⽰例:这是我的代码⽰例:8293637383946474849565758596061public enum PermissionItem{ User, Product, Contact, Review, Client}

public enum PermissionAction{ Read, Create,}

public class AuthorizeAttribute : TypeFilterAttribute{ public AuthorizeAttribute(PermissionItem item, PermissionAction action) : base(typeof(AuthorizeActionFilter)) { Arguments = new object[] { item, action }; }}

public class AuthorizeActionFilter : IAuthorizationFilter{ private readonly PermissionItem _item; private readonly PermissionAction _action; public AuthorizeActionFilter(PermissionItem item, PermissionAction action) { _item = item; _action = action; } public void OnAuthorization(AuthorizationFilterContext context) { bool isAuthorized = MumboJumboFunction(, _item, _action); // :)

if (!isAuthorized) { = new ForbidResult(); } }}

public class UserController : BaseController{ private readonly DbContext _context;

public UserController( DbContext context) : base() { _logger = logger; }

[Authorize(, )] public async Task Index() { return View(await _Async()); }}

发布者:admin,转转请注明出处:http://www.yc00.com/news/1687249261a2.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信