Steven Sann
Steven Sann

Reputation: 578

authorize attribute for users could not found in asp.net core

I just want to authorize to users for my action like

[Authorize(Users = "anupam,ashwin")]  
public ActionResult AddArticle()  
{  
   return View();  
}  

Reference Here

But I only found Roles in AuthorizeAttribute as shown below

enter image description here

I want to use Users attribute for Authorize, is there any alternative way in asp.net core ??

Upvotes: 0

Views: 2277

Answers (1)

Chris Pratt
Chris Pratt

Reputation: 239400

The article you're referencing is for ASP.NET MVC, not ASP.NET Core. In general, you should ignore anything there, as it's no longer applicable.

It would seem ASP.NET Core removed support for specifying Users in AuthorizeAttribute (though, frankly, I was unaware that ASP.NET MVC had it in the first place). It's possible to mimic this functionality via policies, though:

services.AddPolicy("MustBeJoeOrBob", p =>
    p.RequireAssertion(c =>
        new[] { "Joe", "Bob" }.Contains(c.User.Identity.Name)));

Then:

[Authorize(Policy = "MustBeJoeOrBob")]

However, if it isn't clear, this requires a fair bit of hard-coding and you'd need a separate policy for each distinct group of users. For example, if a different action could only be accessed by Joe and Mary, but not Bob, then you'd need to add a "MustBeJoeOrMary" policy, too. That can get tedious quick.

There is technically a way to have one policy handle any given list of users, but implementation is non-trivial. You essentially have to create custom AuthorizeAttribute, which then allows you to pass different kinds of data. However, the actual authorization still needs to be policy-based, so you basically just map passed in value to a custom policy name with a standard prefix. For example:

public class UsersAuthorizeAttribute : AuthorizeAttribute
{
    private const string PolicyPrefix = "MustBeUsers"

    public UsersAuthorizeAttribute(string users)
    {
        Users = users;
    }

    public string Users
    {
        get => Policy.Substring(PolicyPrefix.Length);
        set => $"{PolicyPrefix}{value}";
    }
}

Then, you can apply the attribute like:

[UsersAuthorize("Joe,Bob")]

This effectively just does the same thing as:

[Authorize(Policy = "MustBeUsersJoe,Bob")]

In other words, it's just a short hand way of creating a "dynamic" policy name. However, you now need a policy handler, so you're either back in the same boat of creating one for every possible combination of users, or you have to create a custom policy provider. That policy provider then can look at just the prefix, "MustBeUsers", and use something like a MustBeUsersAuthorizationHandler to satisfy the policy, passing in the rest of the policy name (i.e. the actual usernames) into the handler for it to do it's evaluation on. However, ASP.NET Core will only use one policy provider, so once you sub in a custom one, you also need to ensure that it supports other policies, as well, or at least delegates policy handling to a default provider internally. The docs go into greater detail, but suffice to say, you can start to get into the weeds quick.

Honestly, this whole approach feels like a huge hack, and I'm actually very surprised that the docs actually describe how to achieve it in detail. If you really need something like this, it might make sense, but in your scenario, I think you're missing a crucial thing: you can just use roles.

If you want only Joe and Bob to be able to access a particular action, then simply create a role and assign them to that. Then specify that role:

[Authorize(Roles = "JoeAndBobsRole")]

This is what roles are intended for, and you're essentially trying to side step that and implement the same functionality in a different way. That's honestly probably why Users doesn't exist as an option in ASP.NET Core in the first place.

Upvotes: 2

Related Questions