How do you create a custom AuthorizeAttribute in ASP.NET Core?
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 policy design is a great addition to the framework and the ASP.Net Security Core team should be commended for its introduction. That said, it isn't well-suited for all cases. The shortcoming of this approach 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 the ASP.Net Core Security team recommends never creating your own solution, in some cases this may be the most prudent option with which to start.
The following is an implementation which uses the IAuthorizationFilter
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 : IAuthorizationFilter
{
readonly Claim _claim;
public ClaimRequirementFilter(Claim claim)
{
_claim = claim;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
var hasClaim = context.HttpContext.User.Claims.Any(c => c.Type == _claim.Type && c.Value == _claim.Value);
if (!hasClaim)
{
context.Result = new ForbidResult();
}
}
}
[Route("api/resource")]
public class MyController : Controller
{
[ClaimRequirement(MyClaimTypes.Permission, "CanReadResource")]
[HttpGet]
public IActionResult GetResource()
{
return Ok();
}
}
DotNet Core Custom Authorize Attribute using Route Params
I was able to solve my problem by doing the following:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class UserAuthorizationAttribute : AuthorizeAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
// Here I can get userId from my params.
var userId = context.RouteData.Values["userId"].ToString();
// It is then being checked against current user claims.
// The user is only authorized if the userId is equals to ClaimsType.Value and claims Type is equals to NameIdentifier.
var isUserAuthorized = context.HttpContext.User.Claims.Any(c => c.Type == ClaimTypes.NameIdentifier && c.Value == userId);
if (!isUserAuthorized)
{
context.Result = new UnauthorizedResult();
}
}
}
Pass connection string to custom AuthorizeAttribute in asp.net core
Use the AuthorizationFilterContext.HttpContext.RequestServices.GetService
method from the context argument passed into your OnAuthorization method:
public void OnAuthorization(AuthorizationFilterContext context)
{
...
if (user.Identity.IsAuthenticated)
{
var connectionString = context.HttpContext.RequestServices
.GetService(typeof(IConfiguration))
.GetConnectionString("EmployeeDBConnection");
// GetConnectionString is an extension method, so add
// using Microsoft.Extensions.Configuration
...
}
}
Using this technique, you could also simply use your DbContext
as well.
Custom Authorize attribute - ASP .NET Core 2.2
You can use IAuthorizationPolicyProvider
to get the policy and then use ClaimsAuthorizationRequirement.ClaimType
to get a claim name. And since it has async API, it is better to use IAsyncAuthorizationFilter
instead of IAuthorizationFilter
. Try this:
public class CustomAuthorizeAttribute : AuthorizeAttribute, IAsyncAuthorizationFilter
{
public async Task OnAuthorizationAsync(AuthorizationFilterContext authorizationFilterContext)
{
var policyProvider = authorizationFilterContext.HttpContext
.RequestServices.GetService<IAuthorizationPolicyProvider>();
var policy = await policyProvider.GetPolicyAsync(UserPolicy.Read);
var requirement = (ClaimsAuthorizationRequirement)policy.Requirements
.First(r => r.GetType() == typeof(ClaimsAuthorizationRequirement));
if (authorizationFilterContext.HttpContext.User.Identity.IsAuthenticated)
{
if (!authorizationFilterContext.HttpContext
.User.HasClaim(x => x.Value == requirement.ClaimType))
{
authorizationFilterContext.Result =
new ObjectResult(new ApiResponse(HttpStatusCode.Unauthorized));
}
}
}
}
How do I create a custom Authorize attribute that does not depend on claims in ASP.NET Core?
You can simply create Authorization Filter
public class CustomAuthorizationFilter : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
string id = context.HttpContext.Request.Query["id"]?.ToString();
if (!string.IsNullOrEmpty(id))
{
// Authorization logic
}
}
}
Related Topics
The Entity Cannot Be Constructed in a Linq to Entities Query
How to Pass Data (And References) Between Scenes in Unity
Difference Between I++ and ++I
What Is the Best Workaround For the Wcf Client 'Using' Block Issue
Protect .Net Code from Reverse Engineering
Best Way to Implement Keyboard Shortcuts in a Windows Forms Application
The Provider Is Not Compatible With the Version of Oracle Client
Increase Upload File Size in ASP.NET Core
Possible to Call C++ Code from C#
How to Use Reflection to Call a Generic Method
Difference Between a Reference Type and Value Type in C#
An Async/Await Example That Causes a Deadlock
Best Way to Parse Command Line Arguments in C#
Calculate Difference Between Two Dates (Number of Days)
Do Httpclient and Httpclienthandler Have to Be Disposed Between Requests