We have implemented a zero-configuration, easy to use Authorization and permission system. There are multiple ways to ensure that a user does not have access to pages or Api methods they shouldn't have access to. All of them are implemented using the
[Authorize] attribute. There are three flavors of this attribute.
[Authorize]This is the simplest ones and it simply checks that the current user is logged in.
[Authorize(Roles="admin")]When applied, this checks that the current logged in user has the role of an admin. Specify multiple roles by separating them via commas.
[Authorize(Internal.Permissions.Administration.View)]This is how we implemented permissions (also known as policies). When applied, this checks that the current logged in user has the given permission.
If you want to apply an authorization rule on a Blazor page, use
@attribute [Authorize(Internal.Permissions.Administration.View)], or any other flavor of the
Authorize attribute. Similarly, if you want to apply an authorization rule on a controller method (or on the entire controller), use
[Authorize(Internal.Permissions.Administration.View)]. See the existing code for examples.
Roles and Permission Configuration
As mentioned above, the system we have implemented is zero-configuration. All roles are defined in
ServiceConfiguration.Identity.Roles and will be automatically created in
IdentityDataInitializer.SeedRoles if they do not exist.
Similarly, permissions are auto-generated, but the mechanism involved is a bit more complex. First, all permissions need to be defined in
Internal\Permissions\Permissions.cs as constants. You then decorate each constant by using the
PermissionRoles attribute and specifying one or more comma separated roles as the attribute argument. You will be referencing these constants whenever you use the
[Authorize] attribute with a policy specification. These constants are auto-discovered by means of reflection, so make sure they are inside public classes in the
AppName.Internal.Permissions namespace. The constants must also be public. You can set the
PermissionRoles attribute on a given class (optional), in which case it will take all the public constants in that class and create the appropriate permissions. You an also override an individual permission constant.
The magic happens inside the
PermissionPolicyProvider classes by means of the concept of Claims. We won't go into great detail here, but if you are interested, check Microsoft's documentation. When creating a new permission, you can look at the
AspNetRoleClaims table to ensure that it is auto-created. If it is not there, your permission will not work when applied to the
Managing User Roles
By default all registered users are given the User role, as defined in
ServiceConfiguration.IdentityConfiguration.UserRoleName. You can modify this behavior in
Register.razor, specifically the
SubmitClicked method. To modify the roles of one or more users, head over to the Users page (must be logged in as an Admin). You can assign one or more roles to one or more users. These users will then get the permissions that were configured via the
Table of Contents
- Initial Setup
- Project Structure
- Entity Framework
- User Interface
- Email Service
- Background Workers
- Creating a new Page
- Publishing to Azure