Skadoosh
Skadoosh

Reputation: 2623

Attribute-based authorization in DotNetCore API

I am converting .NET APIs code to .NET Core APIs. There are a few APIs that have attribute authorization in the older system. As I understand, .NET Core doesn't have attribute authorization. So, how can I accomplish the same?

I'll also give an example of the attribute from the older system below:

[RequiredPermission("100,101,102")]

I have been reading about policy-based authorization hoping to accomplish what the older system did. Basically, I would like to pass in a list of allowed permissions to an API controller action. Every call would get evaluated against that list to see if the user has those permissions.

Upvotes: 1

Views: 390

Answers (1)

itminus
itminus

Reputation: 25350

To be compatible with the older system, you can create a simple Authorization Filter :

public class RequiredPermissionAttribute : Attribute, IAsyncAuthorizationFilter{

    public RequiredPermissionAttribute(string permissions)
    {
        this.Permissions = string.IsNullOrEmpty(permissions) ?
            new List<string>():
            permissions.Split(",").Select(p =>p.Trim()).ToList();
    }

    public IList<string> Permissions {get;set;}

    public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {
        var user = context.HttpContext.User;

        var authZService = context.HttpContext.RequestServices.GetRequiredService<IAuthorizationService>();
        var accessable = await authZService.AuthorizeAsync(user,this.Permissions,"Require Permissions Policy");
        if(!accessable.Succeeded){
            context.Result =  new ForbidResult();
        }
    }
}

and now you can use the authorization filter to intercept request :

[RequiredPermission("101,102,103")]
public IActionResult Contact()
{
    ViewData["Message"] = "Your contact page.";

    return View();
}

Of course , we need to register the policy firstly . :

services.AddAuthorization( o=> {
    o.AddPolicy("Require Permissions Policy", pb =>{
        pb.RequireAssertion(async context =>{
            var user = context.User;
            var permissions=context.Resource as IList<string>;
            if(permissions == null || permissions.Count()==0 ){ return true; }
            if(user.Claims.Any( c => c.Type=="MyCustomClaimType" && permissions.Any(p => p.Equals(c.Value)) ))
            {
                return true;
            }
            return false;
        });
    });
});

For a testing purpose, I just add a simple function to check the policy, you can custom the authorization process as you like.

Upvotes: 2

Related Questions