15

This is not a duplicate question or rather the solutions given in other solutions have not worked.

Lets say there is a controller

[Authorize(Roles=//set dynamically)]
public IActionResult DashBoard(LoginModel model)
{
}

I have tried the solutions in the following questions

  1. Add roles to authorize attribute

  2. dynamically assign controller action permissions to roles

  3. dynamically add roles to authorize attribute for controller (Error: Handle method - no suitable method found to override )

  4. can policy based authorization be more dynamic

All of these solutions do not work as either the methods overridden in the interfaces are not present (eg. authorizeAttribute does not contain a definition for AuthorizeCore) or in some cases IServiceCollection services does not contain a particular method

3
  • 1
    The answer here is really a good one ... stackoverflow.com/a/31465227/4755704 Commented Jun 28, 2017 at 6:34
  • I tried this already. AuthorizationContext definition is not found and as for the handle method it says no suitable method found to override Commented Jun 28, 2017 at 6:38
  • refer to github.com/VahidN/DNTIdentity Commented Dec 9, 2018 at 10:29

3 Answers 3

20

You can't do that. [Authorize(Roles=//set dynamically)] must be know at compile time. Also using roles for this very reason is discouraged as pointed in blowdart's linked post from comments.

Instead, you should use claims and policies. Claims are fine grained permissions, for example "CreateCustomer" or "DeleteCustomer" or "ViewDashboard".

So you have to use it like

[Authorize(Policy = "ViewDashboard")]

These policies need to be know at compile time.

public class ViewDashboardRequirement : AuthorizationHandler<ViewDashboardRequirement>, IAuthorizationRequirement
{
    public override void Handle(AuthorizationContext context, ViewDashboardRequirement requirement)
    {
        if (context.User.HasClaim(c => c.Type == "dashboard:read"))
        {
            context.context.Succeed(requirement);
            return;
        }

        // only call fail if you do not want that other AuthorizationHandler may succeed with 
        // a different requirement
        // context.Fail();
    }
}

For an example on how to generate a generic handler (instead of writing a new Handler for each policy) see my answer here.

This will allow you to create configurable roles. Now you can create roles which consists as a bag of claims. Each claim may be one policies. When the user logs in, you add the claims that belong to a role to the list of users claims.

i.e.

  • Support: ViewDashboard, ViewCustomers, ViewContacts, ManageCases (support tickets)
  • Manager: ViewDashboard, ManageCustomers (View, Edit, Delete), ManageContacts (View, Edit, Delete)
  • Administrator: ManageDashboard (View, Edit)

etc.

Update from Comments.

You should be able to utilize ASP.NET Core Identity's claim and roleclaim abilities w/o changing a line of code, therefor you have the IdentityRole and IdentityRoleClaim classes. At runtime, you add a new IdentityRole (i.e. "Manager") and then add multiple IdentityRoleClaim (one for each permission/policy)

Sign up to request clarification or add additional context in comments.

9 Comments

The problem Im facing is that in the requirement class I need to call db. for which i need to add a datacontext. but any object created of this class will need a datacontecxt object
No, you don't need to call db there. Requirement should operate on the user claims. When you log in, you put the required claims into the the ClaimsPrinicipal. Then every time the user authenticates you can access the claims from within HttpContext.User.HasClaim(...) or HttpContext.User.FindFirst(...). A role then is only a bunch of claims which can be configured at runtime (i.e. adding new roles means creating a role and adding certain claims to it
A "claim" is a little more then a specific permission like "ViewCustomers" or "ManageCustomers"
@Lobato: Claims are there to see if they have access to the page/webapi. To filter data, you'd need some criteria on the database, such as "ownedBy" and "groupId", organizationid or compare that with the parent organization (if you have something similar to the way Microsoft Dynamics manages access to data).You can have a claims-array with the name or id of the roles,if you adjust the view based on a role, but that assumes that you know the roles at compile time. That's why using Roles property of AuthorizeAttribute isn't recommended anymore. Claims are just more dynamic.
@Lobato: Well yea. On your DashController/actions you have the [Authorize(Policy = "ViewDashboard")] on there which checks if the user has dashboard:view policy. Do not matter which group he belongs to, as long as he has the claim, he can access that action or controller. Inside it, you need to read his groupis, groupids, userid, the company he belongs or whatever you need (either from claims or just grab his id and get it from your database) and apply that to the data or database queries
|
0

i think you have to use Policy instead if role for authorization. in fact one of the benefit of the policy based vs role based is this.

Comments

-6
public IActionResult Validate(LoginDetails userobj)
       {
          LoginDetails user = new LoginDetails();
         var checklogin = from s in appDbContext.loginDetails where s.UserName == userobj.UserName && s.Password == userobj.Password select s;

               if (checklogin != null && checklogin.Count() > 0)
               {
                   if (checklogin.FirstOrDefault().Role == 1)
                   {
                       return RedirectToAction("Home");
                   }
                   else if (checklogin.FirstOrDefault().Role == 2)
                   {
                       var UserId = checklogin.FirstOrDefault().LoginId;
                       HttpContext.Session.SetInt32("UserId", UserId);
                       return RedirectToAction("Index1");
                   } 
           }

           return RedirectToAction("Failed");
       }

1 Comment

Please add verbal description to your answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.