问:

I'm trying to make a custom authorization attribute in ASP.NET Core.

In previous versions it was possible to override bool AuthorizeCore(HttpContextBase httpContext).

But this no longer exists in AuthorizeAttribute.

What is the current approach to make a custom AuthorizeAttribute?

What I am trying to accomplish: I am receiving a session ID in the Header Authorization. From that ID I'll know whether a particular action is valid.

回答:

I'm the asp.net security person. Firstly let me apologise that none of this is documented yet outside of the musicstore sample or unit tests, and it's all still being refined in terms of exposed APIs.

We don't want you writing custom authorize attributes. If you need to do that we've done something 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. Your session ID would be the basis for an identity. If you wanted to use the Authorize attribute you'd write an authentication middleware to take that header and turn it into an authenticated ClaimsPrincipal. You would then check that inside an authorization 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;

public class Over18Requirement : AuthorizationHandler<Over18Requirement>, IAuthorizationRequirement
{
public override void Handle(AuthorizationContext context, Over18Requirement requirement)
{
if (!context.User.HasClaim(c => c.Type == ClaimTypes.DateOfBirth))
{
context.Fail();
return;
} var dateOfBirth = Convert.ToDateTime(context.User.FindFirst(c => c.Type == ClaimTypes.DateOfBirth).Value);
int age = DateTime.Today.Year - dateOfBirth.Year;
if (dateOfBirth > DateTime.Today.AddYears(-age))
{
age--;
} if (age >= 18)
{
context.Succeed(requirement);
}
else
{
context.Fail();
}
}
}
}

Then in your ConfigureServices() function you'd wire it up

options.AddPolicy("Over18",
policy => policy.Requirements.Add(new Authorization.Over18Requirement()));

And finally apply it to a controller or action method with

[Authorize(Policy = "Over18")]

回答:

What is the current approach to make a custom AuthorizeAttribute

Easy: don't create your own AuthorizeAttribute.

For pure authorization scenarios (like restricting access to specific users only), the recommended approach is to use the new authorization block: https://github.com/aspnet/MusicStore/blob/master/src/MusicStore/Startup.cs#L118-L121

public class Startup {
public void ConfigureServices(IServiceCollection services) {
services.Configure<AuthorizationOptions>(options => {
options.AddPolicy("ManageStore", policy => policy.RequireClaim("Action", "ManageStore"));
});
}
} public class StoreController : Controller {
[Authorize(Policy = "ManageStore"), HttpGet]
public async Task<IActionResult> Manage() { ... }
}

For authentication, it's best handled at the middleware level.

What are you trying to achieve exactly?

回答:

You can create your own AuthorizationHandler that will find custom attributes on your Controllers and Actions, and pass them to the HandleRequirementAsync method.

public abstract class AttributeAuthorizationHandler<TRequirement, TAttribute> : AuthorizationHandler<TRequirement> where TRequirement : IAuthorizationRequirement where TAttribute : Attribute
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement)
{
var attributes = new List<TAttribute>(); var action = (context.Resource as AuthorizationFilterContext)?.ActionDescriptor as ControllerActionDescriptor;
if (action != null)
{
attributes.AddRange(GetAttributes(action.ControllerTypeInfo.UnderlyingSystemType));
attributes.AddRange(GetAttributes(action.MethodInfo));
} return HandleRequirementAsync(context, requirement, attributes);
} protected abstract Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement, IEnumerable<TAttribute> attributes); private static IEnumerable<TAttribute> GetAttributes(MemberInfo memberInfo)
{
return memberInfo.GetCustomAttributes(typeof(TAttribute), false).Cast<TAttribute>();
}
}

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 custom attribute.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, 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

public class PermissionAuthorizationRequirement : IAuthorizationRequirement
{
//Add any custom requirement properties if you have them
}

Then create the AuthorizationHandler for your custom attribute, inheriting the AttributeAuthorizationHandler that we created earlier. It will be passed an IEnumerable for all your custom attributes in the HandleRequirementsAsync method, accumulated from your Controller and Action.

public class PermissionAuthorizationHandler : AttributeAuthorizationHandler<PermissionAuthorizationRequirement, PermissionAttribute>
{
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionAuthorizationRequirement requirement, IEnumerable<PermissionAttribute> attributes)
{
foreach (var permissionAttribute in attributes)
{
if (!await AuthorizeAsync(context.User, permissionAttribute.Name))
{
return;
}
} context.Succeed(requirement);
} private Task<bool> AuthorizeAsync(ClaimsPrincipal user, string permission)
{
//Implement your custom user permission logic here
}
}

And finally, in your Startup.cs ConfigureServices method, add your custom AuthorizationHandler to the services, and add your Policy.

        services.AddSingleton<IAuthorizationHandler, PermissionAuthorizationHandler>();

        services.AddAuthorization(options =>
{
options.AddPolicy("Permission", policyBuilder =>
{
policyBuilder.Requirements.Add(new PermissionAuthorizationRequirement());
});
});

Now you can simply decorate your Controllers and Actions with your custom attribute.

[Permission("AccessCustomers")]
public class CustomersController
{
[Permission("AddCustomer")]
IActionResult AddCustomer([FromBody] Customer customer)
{
//Add customer
}
}
回答:

The approach recommended by the ASP.Net Core team is to use the new policy design which is fully documented here.  The basic idea behind the new approach is to use the new [Authorize] attribute to designate a "policy" (e.g. [Authorize( Policy = "YouNeedToBe18ToDoThis")] where the policy is registered in the application's Startup.cs to execute some block of code (i.e. ensure the user has an age claim where the age is 18 or older).

The shortcoming of this approach, however, is that it fails to provide a convenient solution for the most common need of simply asserting that a given controller or action requires a given claim type.  In the case where 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 repetitive one-to-one mappings between a policy name and a claim name (e.g. options.AddPolicy("CanUpdateOrder", policy => policy.RequireClaim(MyClaimTypes.Permission, "CanUpdateOrder));), or writing some code to perform these registrations at run time (e.g. read all claim types from a database and perform the aforementioned call in a loop).  The problem with this approach for the majority of cases is that it's unnecessary overhead.

While it seems the ASP.Net Core Security team would have you believe you should never seek to create your own solution, in most cases this will be the most prudent option to start with.

The following is an implementation which relies upon action filters to provide a simple way to express a claim requirement for a given controller or action:

public class ClaimRequirementAttribute : TypeFilterAttribute
{
public ClaimRequirementAttribute(string claimType, string claimValue) : base(typeof(ClaimRequirementFilter))
{
Arguments = new object[] {new Claim(claimType, claimValue) };
}
} public class ClaimRequirementFilter : IAsyncActionFilter
{
readonly Claim _claim; public ClaimRequirementFilter(Claim claim)
{
_claim = claim;
} public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var hasClaim = context.HttpContext.User.Claims.Any(c => c.Type == _claim.Type && c.Value == _claim.Value);
if (!hasClaim)
{
context.Result = new UnauthorizedResult(); }
else
{
await next();
}
}
} [Route("api/resource")]
public class MyController : Controller
{
[ClaimRequirement(MyClaimTypes.Permission, "CanReadResource")]
[HttpGet]
public IActionResult GetResource()
{
return Ok();
}
}

[转]How do you create a custom AuthorizeAttribute in ASP.NET Core?的更多相关文章

  1. 002.Create a web API with ASP.NET Core MVC and Visual Studio for Windows -- 【在windows上用vs与asp.net core mvc 创建一个 web api 程序】

    Create a web API with ASP.NET Core MVC and Visual Studio for Windows 在windows上用vs与asp.net core mvc 创 ...

  2. 004.Create a web app with ASP.NET Core MVC using Visual Studio on Windows --【在 windows上用VS创建mvc web app】

    Create a web app with ASP.NET Core MVC using Visual Studio on Windows 在 windows上用VS创建mvc web app 201 ...

  3. [转]Writing Custom Middleware in ASP.NET Core 1.0

    本文转自:https://www.exceptionnotfound.net/writing-custom-middleware-in-asp-net-core-1-0/ One of the new ...

  4. [译]Writing Custom Middleware in ASP.NET Core 1.0

    原文: https://www.exceptionnotfound.net/writing-custom-middleware-in-asp-net-core-1-0/ Middleware是ASP. ...

  5. Part 13 Create a custom filter in AngularJS

    Custom filter in AngularJS 1. Is a function that returns a function 2. Use the filter function to cr ...

  6. How could I create a custom windows message?

    [问题] Our project is running on Windows CE 6.0 and is written in C++ . We have some problems with the ...

  7. [转]Create Custom Exception Filter in ASP.NET Core

    本文转自:http://www.binaryintellect.net/articles/5df6e275-1148-45a1-a8b3-0ba2c7c9cea1.aspx In my previou ...

  8. [Angular] Create a custom validator for reactive forms in Angular

    Also check: directive for form validation User input validation is a core part of creating proper HT ...

  9. [Angular] Create a custom validator for template driven forms in Angular

    User input validation is a core part of creating proper HTML forms. Form validators not only help yo ...

随机推荐

  1. JavaScript权威设计--事件冒泡,捕获,事件句柄,事件源,事件对象(简要学习笔记十八)

    1.事件冒泡与事件捕获 2.事件与事件句柄   3.事件委托:利用事件的冒泡技术.子元素的事件最终会冒泡到父元素直到跟节点.事件监听会分析从子元素冒泡上来的事件. 事件委托的好处:     1.每个函 ...

  2. Jquery Uploadify3.21.与2.1版本 使用中存在的问题--记录三

    Jquery Uploadify是个上传插件. 2.1版本与3.2.1版本有很大区别,方法名跟参数变动较大 1.uploader:该属性是用来存放swf的路径,这个swf就是一个Flash的一个图标, ...

  3. 初始Bootstrap

    使用示例 ①下载Bootstrap框架 网址:http://v3.bootcss.com/getting-started/#download ②解压得到三个文件     ③将文件添加进项目后,在页面中 ...

  4. 读书笔记--SQL必知必会07--创建计算字段

    7.1 计算字段 字段(field),基本与列(column)含义相同. 利用计算字段可以直接从数据库中检索出转换.计算或格式化过的数据. 计算字段不实际存在于数据库表中,是运行时在SELECT语句内 ...

  5. 你真的会玩SQL吗?你所不知道的 数据聚合

    你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...

  6. @Autowired注解的使用

    使用Spring时,通过Spring注入的Bean一般都被定义成private,并且要有getter和setter方法,显得比较繁琐,增加了代码量,而且有时会搞忘造成错误. 可以使用@Autowire ...

  7. JavaWeb_day02_登录校验_查询所有员工信息_DeBug

    本文为博主辛苦总结,希望自己以后返回来看的时候理解更深刻,也希望可以起到帮助初学者的作用. 转载请注明 出自 : luogg的博客园 谢谢配合! WEB_day02 servlet 协议转对象 服务器 ...

  8. Android Time类 奇葩的设定

    Android 的Time.MONTH默认是0-11表示1-12月,小白表示坑爹啊,浪费多少精力啊.

  9. 严重: Exception sending context initialized event to listener instance of class

    问题描述:Exception sending context initialized event to listener instance of class org.springframework.w ...

  10. Windows Form调用R进行绘图并显示

    R软件功能非常强大,可以很好的进行各类统计,并能输出图形.下面介绍一种R语言和C#进行通信的方法,并将R绘图结果显示到WinForm UI界面上. 1 前提准备 安装R软件,需要安装32位的R软件,6 ...