Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET Core 3.1 Web Api authorization on model property level

I have a web api with basic jwt authentication and role based authorization. Now I want to restrict certain fields from being edited by users that are in the role user, because the route based authorization is not enough.

class Account {
    public int Id {get; set;}
    public string Email {get; set;}
    public string Password {get; set;}
    public bool Enabled {get; set;} // <- this field should only be editable by an admin or manager
    public int RoleId {get; set;} // <- this field should only be editable by an admin
}

When the user is in the role user he is only allowed to change his email address and his password, but only for his account. When he is in the role manager he should be able to edit the fields email, password and enabled but only for accounts that are in the user role. An admin can edit every field from every user.

Is there anything that would solve my problem, for example something like this:

class Account {
    public int Id {get; set;}
    public string Email {get; set;}
    public string Password {get; set;}

    [Authorize(Roles = "Admin,Manager")]
    public bool Enabled {get; set;} // <- this field should only be editable by an admin or manager

    [Authorize(Roles = "Admin")]
    public int RoleId {get; set;} // <- this field should only be editable by an admin
}

More infos about my project: - ASP.NET Core 3.1 - I use Entity Framework Core with a Postgres database - For authentication I use basic jwt bearer authentication

like image 555
D.W Avatar asked Jun 08 '20 13:06

D.W


1 Answers

So, I think you has incorrect understanding of Authtorize working.

This attribute uses for Controllers. You can create multiple controllers and set for each method different ROLES to specify what Roles can call this method.

It's not correct to specify it on Dto (Data Transfer Objects) classes.

But you can make some interesting solution with 2 controllers and inheritance.

//Account dto for edit
class AccountEditDto {
    public int Id {get; set;}
    public string Email {get; set;}
    public string Password {get; set;}
}

//Controller to edit account
[Route("all/account_controller")]
public class AccountController : Controller
{
    
    public ActionResult EditAccount(AccountEditDto accountDto)
    {
        //do something
    }
}

Then for create manager roles setup something like this :

//Account dto for edit
class AccountManagerEditDto : AccountEditDto {
    public bool Enabled {get; set;} 
}

//Controller admin to edit account
[Area("Manager")]
[Route("manager/account_controller")]
public class AccountManagerController : AccountController
{
    [Authorize(Roles = "Manager")]
    public ActionResult EditAccount(AccountManagerEditDto accountDto)
    {
        //Do something
    }
}

Then for create admin roles setup something like this :

//Account dto for edit
class AccountAdminEditDto : AccountManagerEditDto {
    public int RoleId {get; set;} 
}

//Controller admin to edit account
[Area("Admin")]
[Route("admin/account_controller")]
public class AccountAdminController : AccountController
{
    [Authorize(Roles = "Admin")]
    public ActionResult EditAccount(AccountAdminEditDto accountDtp)
    {
        //Do something
    }
}

Then you can use than pattern of URL for call controller methods:

http://localhost/{role}/accont_controller/edit
like image 135
TemaTre Avatar answered Oct 12 '22 13:10

TemaTre