locked
ASP.NET Core 2.x Identity - Multiple "Zones" RRS feed

  • Question

  • User-482460790 posted

    We've got an old webforms app that runs most of our business and we're in the process of re-writing this in ASP.NET Core for a number of reasons.  One of the things we'd like to do is migrate away from our homegrown security implementation and instead rely on ASP.NET Identity.  Our primary issue is that we have tens of thousands of accounts, each with 1 or more users assigned.  Each account has the same roles available to it (AccountOwner, SupportAdmin, BillingAdmin, etc).  This is defined in our Roles table as follows:

    RoleID (AutoInc), AccountID, RoleName, RoleDescription

    If a role is available to ALL accounts, we enter it is as follows:

    0, AccountAdmin, Account Administrator

    0, SupportAdmin, Support Administrator

    0, BillingAdmin, Billing Administrator

    ... And so on, we have about 10 roles that we assign this way and are available to every single account we have.  We've got a couple of other accounts (primarily for our employees) that have more specific roles, for example:

    1500, Employee, CompanyEmployee

    Currently, we call a routine similar to this:

    If(user.isinrole(UserID, AccountID, "AccountOwner")) {}...

    From what I can tell, something like this is not available in ASP.NET Identity, making managing multiple accounts difficult.

    This seems like it would be somewhat common, has anyone done this successfully (and securely) and if so, how?  Are we better off using ASP.Net Identity for authentication and our own routines for authorization?  What we've come up with is either:

    1) Extending the Identity classes to include what we want, which doesn't appeal to us much as now we're relying on our custom code again vs a hardened authentication system

    or 

    2) Every time an account is created, create 10-15 new roles, for example: 1242_AccountOwner, etc (AccountOwner Role for accountID 1242).

    Any input would be greatly appreciated.

    Monday, June 24, 2019 6:08 AM

All replies

  • User1120430333 posted

    Have you actually seen such links about Roles being used in Identity?

    https://www.c-sharpcorner.com/article/getting-started-with-asp-net-core-2-0-identity-and-role-management/

    Sure you would have to probably make some code adjustments and also load and convert your role records to load them into the Role table in the Identity database, but I don' see why you couldn't do it and use multiple roles for a user.

    https://docs.microsoft.com/en-us/aspnet/core/security/authorization/roles?view=aspnetcore-2.2

    Monday, June 24, 2019 8:38 AM
  • User-482460790 posted

    Yes, I understand how roles work in ASP.NET Core.  The issue we have is that we have s third component we're comparing against, an AccountID.  So Identity would need to check if User 214 has Billing Permissions on Account 53, for example.

    Monday, June 24, 2019 2:34 PM
  • User475983607 posted

    MarkM_SS

    Yes, I understand how roles work in ASP.NET Core.  The issue we have is that we have s third component we're comparing against, an AccountID.  So Identity would need to check if User 214 has Billing Permissions on Account 53, for example.

    ASP.NET Core Identity has very robust claim based and policy based authorization which allows you to write custom logic.

    https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies?view=aspnetcore-2.2

    Usually, you'll use the [Authorize] attribute to secure actions which allows for multiple roles/claims separated by a comma.  If you need to check is a user is in a role then it a very simply LINQ expression against the user's roles/claims.

    Monday, June 24, 2019 3:05 PM
  • User1120430333 posted

    MarkM_SS

    Yes, I understand how roles work in ASP.NET Core.  The issue we have is that we have s third component we're comparing against, an AccountID.  So Identity would need to check if User 214 has Billing Permissions on Account 53, for example.

    I think you are talking about business logic that you're going to have to implement, beyond Identity and ASP.NET MVC authorization.

    Keep in mind where the business logic should be implemented that the controller would call upon.

    https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions-1/overview/understanding-models-views-and-controllers-cs

    <copied>

    An MVC model contains all of your application logic that is not contained in a view or a controller. The model should contain all of your application business logic, validation logic, and database access logic.

    <end>

    It's talking  about a class/object in the Models folder using an Interface that can be DI into the controller and used by the controller. You can also create custom authorization filter as well.

    https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-2.2

    You may not and probably can't lay everything at Identity's door. But you should be able to use Identity and some custom logic you have created to make what you need happen.

    Monday, June 24, 2019 5:27 PM
  • User-1764593085 posted

    Hi MarkM_SS,

    If you would like to check role with your custom logic in controller instead of using [Authorize] attribute, since User.IsInRole  could not be override ,a workaround is to implement your own ClaimsPrincipal and Controller.

    Refer to https://stackoverflow.com/questions/52732431/how-to-custom-override-user-isinrole-in-asp-net-core

     public class CustomClaimsPrincipal : ClaimsPrincipal
        {
    
            private readonly IServiceProvider _serviceProvider;
            public CustomClaimsPrincipal(IPrincipal principal, IServiceProvider serviceProvider) : base(principal)
            {
                _serviceProvider = serviceProvider;
            }
    
            public override bool IsInRole(string role)
            {
                using (var scope = _serviceProvider.CreateScope())
                {
                    var dbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
    var array = role.Split(',');//role array
    //do your check } } }

    `ControllerBase` to change ClaimsPrincipal User to CustomClaimsPrincipal User

    public class ControllerBase : Controller
        {
            public new CustomClaimsPrincipal User => new CustomClaimsPrincipal(base.User, HttpContext.RequestServices);
        }

    Inherit this new ControllerBase for you controller:

    public class HomeController : xxx.ControllerBase
    {
           public IActionResult About()
           {  
              var result = User.IsInRole("UserID,AccountID,AccountOwner");//pass all information in a string
    
              return View();
            }
    }

    Best Regards,

    Xing

    Tuesday, June 25, 2019 9:54 AM
  • User1034446946 posted

    or you could put the account Id as a claim, then have a fixed number of roles, valid the method by role, and validate the content my the claim.

    Tuesday, June 25, 2019 12:52 PM