How to Use Custom Authorize Attribute for Roles as Well as a Specific User

How to use custom Authorize attribute for roles as well as a specific user?

You could write a custom authorize attribute:

public class AuthorizeAdminOrOwnerOfPostAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var authorized = base.AuthorizeCore(httpContext);
if (!authorized)
{
// The user is not authenticated
return false;
}

var user = httpContext.User;
if (user.IsInRole("Admin"))
{
// Administrator => let him in
return true;
}

var rd = httpContext.Request.RequestContext.RouteData;
var id = rd.Values["id"] as string;
if (string.IsNullOrEmpty(id))
{
// No id was specified => we do not allow access
return false;
}

return IsOwnerOfPost(user.Identity.Name, id);
}

private bool IsOwnerOfPost(string username, string postId)
{
// TODO: you know what to do here
throw new NotImplementedException();
}
}

and then decorate your controller action with it:

[AuthorizeAdminOrOwnerOfPost]
public ActionResult EditPosts(int id)
{
return View();
}

What is the code that checks Roles with [Authorize] attribute using custom storage providers for Identity?

I did more research and found a great series of tutorials: https://www.youtube.com/watch?v=Fhfvbl_KbWo&list=PLOeFnOV9YBa7dnrjpOG6lMpcyd7Wn7E8V

In the 4th video at 20:13, the Role in [Authorize] attribute is explained. The [Authorize] attribute uses the role value and simply compares it to the role claim of the identity.

From what I understand, that's really it and implementation of custom storage providers isn't directly related to this.

How to authorize users more than once using custom authorize attribute?

It is unclear exactly why your custom authorize attribute is not working, but it is clear that its implementation is overly complex.

The AuthorizeAttribute has simple boolean function IsAuthorized that you can (and should) override to return whether or not the user is authorized. The base implementation already checks

  1. Whether the user is logged in.
  2. Whether the user is in one of the supplied roles.

so all you need to do is add additional logic when the user is in the Deal User role.

You should never access the static HttpContext.Current member in Web API/MVC. In this particular case, the actionContext is being passed in as a parameter, which you can (and should) use.

using Microsoft.AspNet.Identity;
using System;
using System.Linq;
using System.Net.Http;
using System.Security.Principal;
using System.Web.Http;
using System.Web.Http.Controllers;

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true)]
public class DealManageCustomAuthorizeAttribute : AuthorizeAttribute
{
public DealManageCustomAuthorizeAttribute()
{
// Set the Super Admin and Deal User roles
this.Roles = "Super Admin,Deal User";
}

protected override bool IsAuthorized(HttpActionContext actionContext)
{
// This checks whether the user is logged in, and whether
// they are in the Super Admin or Deal User role.
var isAuthorized = base.IsAuthorized(actionContext);

IPrincipal user = actionContext.ControllerContext.RequestContext.Principal;

// Special case - user is in the Deal User role
if (isAuthorized && user.IsInRole("Deal User"))
{

var queryString = actionContext.Request.GetQueryNameValuePairs()
.ToDictionary(kv => kv.Key, kv => kv.Value, StringComparer.OrdinalIgnoreCase);

// Ensure the query string contains the key "dealId"
if (!queryString.ContainsKey("dealId"))
{
return false;
}

Guid dealId;
if (!Guid.TryParse(queryString["dealId"], out dealId))
{
// If the Guid cannot be parsed, return unauthorized
return false;
}

// Now check whether the deal is authorized.
var userId = user.Identity.GetUserId();

return new Deal(Common.Common.TableSureConnectionString)
.CheckDealByIdAndUserId(dealId, userId);
}

return isAuthorized;
}
}

Using more than one Custom Authorize Attribute

So after much thought on this, I came up with the following solution. I did not add to the current Custom Authorize Attribute I had because this is exclusive to only one module within the site.

However, I do run checks on all pages that the user can hit (barring the Post methods) to determine all cases.

When a user is an Admin, they are given Modify Access. When they are a Read-Only User, they are given no Modify Access. When they are a User, they are checked for Permissions as well, and if they have those Permissions, they are given Modify Access. Otherwise, they are treated like a Read-Only User.

I stored the user's roles and Permissions, as well as if they have Modify Access, within Session. Should the Session(s) not be found, I go back out and add them back in. I also update kill those Sessions if a user's Roles/Permissions are updated in the User Admin area.

Also, in pages that modify something (Add/Edit/Delete), I added a chunk of logic that if they have no Modify Access, they are booted to an Unauthorized Access page.

So far, this seems to have worked out well and has had no issues thus far. I would have much rather added this logic in one place like the Custom Authorize Attribute class, but at the same time, I think it would have been inappropriate to place it there due that it was for only one Module. Thanks.

Custom Authorize attribute role is not working web api authentication

You can refer to this SO question's answer by Derek Greer for Dot Net core, additionally I will reiterate the answer below -

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();
}
}

Part of this answer for .NET Framework-

Recommended Custom Attribute class:

public class CustomAuthorize : System.Web.Http.AuthorizeAttribute
{
private readonly PermissionAction[] permissionActions;

public CustomAuthorize(PermissionItem item, params PermissionAction[] permissionActions)
{
this.permissionActions = permissionActions;
}

protected override Boolean IsAuthorized(HttpActionContext actionContext)
{
var currentIdentity = actionContext.RequestContext.Principal.Identity;
if (!currentIdentity.IsAuthenticated)
return false;

var userName = currentIdentity.Name;
using (var context = new DataContext())
{
var userStore = new UserStore<AppUser>(context);
var userManager = new UserManager<AppUser>(userStore);
var user = userManager.FindByName(userName);

if (user == null)
return false;

foreach (var role in permissionActions)
if (!userManager.IsInRole(user.Id, Convert.ToString(role)))
return false;

return true;
}
}
}

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();
}
}

Custom Authorize Attribute additional Param?

I think you can just add a public property to your custom AuthorizeAttribute.

public class CustomAuthorizeAttribute : AuthorizeAttribute
{
/// <summary>
/// Add the allowed roles to this property.
/// </summary>
public YourCustomRoles RequiredRole;

public int YourCustomValue;

/// <summary>
/// Checks to see if the user is authenticated and has the
/// correct role to access a particular view.
/// </summary>
/// <param name="httpContext"></param>
/// <returns></returns>
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null) throw new ArgumentNullException("httpContext");

// Make sure the user is authenticated.
if (httpContext.User.Identity.IsAuthenticated == false) return false;

// Can use your properties if needed and do your checks
bool authorized = DoSomeCustomChecksHere();

return authorized;
}
}

Usage I think would be (haven't tried it though):

[CustomAuthorizeAttribute (RequiredRole=MyCustomRole.Role1 | MyCustomRole.Role2, YourCustomValue=1234)]


Related Topics



Leave a reply



Submit