Adding your own Custom Authorize Attribute to Asp. Net Core 2.2 and above
The authorize attribute is used to authorize or control user access to application / controller / actions in Asp. Net Core. The built in [Authorize] attribute might not be suitable for all business cases where we must come up with our own implementation. This article explains the different methods in which the custom authorize attribute can be implemented and how the claims from JWT token can be used within it
The custom authorization in Asp .Net Core 2.2 or 3.0 and above can be implemented in two approaches
Approach 1: Extending AuthorizeAttribute along with IAuthorizationFilter will be simplest way to implement custom authorization attribute in Asp. Net Core
Approach 2: Creating Custom Authorization Policy Provider with Authorization Handler, Authorization Requirement and an Authorize Attribute. Refer : https://www.craftedforeveryone.com/custom-authorization-policy-provider-with-custom-authorize-attribute-in-asp-net-core-2-2-and-above/
Approach 1: Extending AuthorizeAttribute along with IAuthorizationFilter in Asp. Net Core
In Asp. Net MVC Framework, simply by extending the AuthrozieAttribute you will be able to override the AuthorizeCore along with HandleUnauthorizedRequest and implement the custom login within it.
In Asp. Net Core the traditional Authorization method has been changed to Policy based Authorization, because of which Authorize Attribute does not have the functions AuthorizeCore or HandleUnauthorizedRequest which was allowing us to implement custom logic previously.
The most recommended way to implement custom authorization attribute is to implement a custom authorization policy provider, which is explained as Approach 2 in this article. But the drawback of this approach is it requires 4 classes to be created and it must be registered in Startup.cs. Understanding the exact workflow will be time consuming for beginners with Asp. Net Core.
To keep it simple and straight forward you can directly create an Attribute Class by extending AuthorizeAttribute and IAuthorizationFilter. The IAuthorizationFilter interface provides an implementation of OnAuthorization in which the custom authorization logic can be implemented.
The return type of OnAuthorization function is void, to return user as Unauthorized after custom validation, you can set the AuthorizationFilterContext context result as Unauthorized or any other custom HttpStatusCode and call the return keywork.
Summarizing the steps that should be followed are
- Create a class which extends AuthorizeAttribute, this will used on top of controller or action like Asp. Net core’s inbuilt [Authorize] attribute.
- Implement the method
OnAuthorization(AuthorizationFilterContext context)
which is part of IAuthorizationFilter interface - Call return keyword without any additional operation for authorized user
- Set AuthorizationFilterContext result as Unauthorized for unauthorized users as
context.Result = new UnauthorizedResult()
Code Implementation for Asp. Net Core 2.2/3.0 and above
The sample Asp. Net Core code shown in this article implements a custom permission based authorize attribute which can be used for both Web API and MVC Projects.
The full working solution can be cloned from GitHub at https://github.com/kaarthikin/asp_net_core_custom_authorize_attribute
Custom Authorize Attribute Code (Permission Based Authorization)
// www.craftedforeveryone.com // Licensed under the MIT License. See LICENSE file in the project root for full license information. using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using System.Linq; namespace CustomAuthorizeAttribute.Approach1 { //Extenting from AuthorizeAttribute or Attribute is upto user choice. //You can consider using AuthorizeAttribute if you want to use the predefined properties and functions from Authorize Attribute. public class A1AuthorizePermission : AuthorizeAttribute, IAuthorizationFilter { public string Permissions { get; set; } //Permission string to get from controller public void OnAuthorization(AuthorizationFilterContext context) { //Validate if any permissions are passed when using attribute at controller or action level if (string.IsNullOrEmpty(Permissions)) { //Validation cannot take place without any permissions so returning unauthorized context.Result = new UnauthorizedResult(); return; } //The below line can be used if you are reading permissions from token //var permissionsFromToken=context.HttpContext.User.Claims.Where(x=>x.Type=="Permissions").Select(x=>x.Value).ToList() //Identity.Name will have windows logged in user id, in case of Windows Authentication //Indentity.Name will have user name passed from token, in case of JWT Authenntication and having claim type "ClaimTypes.Name" var userName = context.HttpContext.User.Identity.Name; var assignedPermissionsForUser = MockData.UserPermissions.Where(x => x.Key == userName).Select(x => x.Value).ToList(); var requiredPermissions = Permissions.Split(","); //Multiple permissiosn can be received from controller, delimiter "," is used to get individual values foreach(var x in requiredPermissions) { if (assignedPermissionsForUser.Contains(x)) return; //User Authorized. Wihtout setting any result value and just returning is sufficent for authorizing user } context.Result = new UnauthorizedResult(); return; } } }
Custom Authorize Attribute Implementation at Controller Action
[A1AuthorizePermission(Permissions = "CanRead")] [HttpGet("{id}")] public ActionResult<string> Get(int id) { return "value"; }