0

I tried searching everywhere on the web, but I can't seem to figure out this important part.

Basically, if we do a DB call each time when checking if a user belongs to a role - this will have negative effect on performance.

I saw code examples listing all user roles, e.g.

var roles = ((ClaimsIdentity)User.Identity).Claims
            .Where(c => c.Type == ClaimTypes.Role)
            .Select(c => c.Value);

the code can be used in controller action, it is also possible to fetch claims the same way in an Attribute Filter.

From this example I infer that Claims come into play (seems to be most performant solution).

I tried to find out if Authorize attribute with Roles verifies user's claims, but the official Microsoft documentation doesn't cover this bit.

AuthorizeAttribute class

Specifies that access to a controller or action method is restricted to users who meet the authorization requirement.

Properties:

Roles - Gets or sets the user roles that are authorized to access the controller or action method.

And that's the extent of what we have.

Alex Herman
  • 2,708
  • 4
  • 32
  • 53

2 Answers2

1

Both the Authorize attribute as e.g. User.IsInRole look at the User.Identity roles claims.

By default the Authority (where the user logs in) will add the roles from the AspNetUserRoles table as claims of type 'http://schemas.microsoft.com/ws/2008/06/identity/claims/role'. See WIF claimtypes members.

The client app will automatically take the information from the token / cookie and convert this as User.Identity. As the claim type matches, the role type claims are mapped as roles.

This means that the app doesn't need access to the user store. In most cases this is also not possible. So it is actually not about performance, but about accessibility. Usually apps don't have access to the Identity context. So UserManager is not an option.

There is however a drawback when using claims. The information is dated. When the user logs in a snapshot of the claims at that time are added to the Identity. If in the meantime claims (or roles) are updated in the database, then these changes are not noted. Only after the user logs in again, the changes become effective.

This means that claims are only suitable for pieces of information that do not (frequently) change unless you find a way to invalidate claims. But that would probably mean to access the database or call the authority.

That's why I wouldn't recommend the use of roles. As roles tend to be used for authorization, but you can't revoke access in the meantime. So until you solve that, you may want to consider an alternative.

Sticking to UserManager is not an alternative, because the context may not be available for all apps.

That's why resource-based authorization may be a solution for you. Please read my answer here for additional thoughts.

  • then in order to increase performance... i guess, identity brings a set of Stored Procedures to perform role check faster? what are your thoughts on this? – Alex Herman Nov 24 '18 at 01:54
  • 1
    I'm not sure what you mean. Identity doesn't have a set of stored procedures, you simply call the UserManager. But you can override the UserStore to use Stored Procedures. But when `User.Identity` is used, the database isn't hit at all (except on login in order to create the token/cookie). If you want to read the roles from the database on each call then you can also think of caching the information so you don't have to call the database each time. –  Nov 24 '18 at 20:11
0

Open your Startup file and change this:

services.AddDefaultIdentity<IdentityUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();

to this:

services.AddIdentity<IdentityUser, IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultUI()
                .AddDefaultTokenProviders();

Then the Roles should start working.

w0051977
  • 15,099
  • 32
  • 152
  • 329