The Authorize attribute, in itself, only serves to specify the kind of authorization you need on a particular page or controller. This attribute is meant to be used in addition to the Identity framework, and can include roles, policies, and authentication schemes.
What you need is to create a bridge between the Identity framework and your database, which can be accomplished with custom UserStore and RoleStore, which is described in details on this page.
To summarize a pretty complex process:
- The
Authorize attribute instructs the browser to authenticate your user
- Your user is redirected to the authentication page
- If it succeeds, you're provided with a
ClaimsPrincipal instance, that you then need to map to your database user, via the custom UserStore
- Your user can then be checked against DB roles
Here's a short example of all this in action (NOT fully complete, because it would be far too much code).
Startup.cs
// This class is what allows you to use [Authorize(Roles="Role")] and check the roles with the custom logic implemented in the user store (by default, roles are checked against the ClaimsPrincipal roles claims)
public class CustomRoleChecker : AuthorizationHandler<RolesAuthorizationRequirement>
{
private readonly UserManager<User> _userManager;
public CustomRoleChecker(UserManager<User> userManager)
{
_userManager = userManager;
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, RolesAuthorizationRequirement requirement)
{
var user = await _userManager.GetUserAsync(context.User);
// for simplicity, I use only one role at a time in the attribute
var singleRole = requirement.AllowedRoles.Single();
if (await _userManager.IsInRoleAsync(user, singleRole))
context.Succeed(requirement);
}
}
public void ConfigureServices(IServiceCollection services)
{
services
.AddIdentity<User, Role>()
.AddUserStore<MyUserStore>()
.AddRoleStore<MyRoleStore>();
// custom role checks, to check the roles in DB
services.AddScoped<IAuthorizationHandler, CustomRoleChecker>();
}
where User and Role are your EF Core entities.
MyUserStore
public class MyUserStore : IUserStore<User>, IUserRoleStore<User>, IQueryableUserStore<User>
{
private Context _db;
private RoleManager<Role> _roleManager;
...
public async Task<User> FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken)
{
// bridge your ClaimsPrincipal to your DB users
var user = db.Users.SingleOrDefault(_ => _.Email.ToUpper() == normalizedUserName);
return await Task.FromResult(user);
}
...
public async Task<bool> IsInRoleAsync(User user, string roleName, CancellationToken cancellationToken)
{
if (roleName == null)
return true;
// your custom logic to check role in DB
var result = user.Roles.Any(_ => _.RoleName == roleName);
return await Task.FromResult(result);
}