-
Notifications
You must be signed in to change notification settings - Fork 160
Setup Permissions
The Permissions explained documentation covers why AuthP uses C# Enum members to secure access to pages, WebAPIs, links etc. This page describes how to build a Enum in a way that is going to work with the AuthP library, and tips on how to organize the Enum members so that they don't become a "big ball of mud" when future Enum members are added.
Some years ago I designed a large application using this Roles/Permissions approach for a client which taught me a lot about how the permissions should be organize. The list below list what I learnt.
-
Features come in groups: A feature we want to secure often has more than one part of it, e.g. a selling feature might have
- SalesRead - user can see what has been sold.
- SalesSell - user can use the app to sell something.
- SalesReturn - user can process a return of a previous sale
- Feature groups should be easy to find: When you have hundreds of feature parts managing it gets harder.
- Feature groups grow over time: This means we need a way to add new feature easily
- Don't delete Obsolete feature parts: If a feature part is obsolete, then don't delete it as its number could be reused, which could cause problems.
-
Adding extra info helps your admin staff: Just a name, like
SalesRead
can be ambiguous, so more data is needed. - Advance Permissions: Permissions protecting features that multi-tenant user shouldn't have access to should be defined as an Advance Permissions.
- You need a SuperAdmin override: When you are setting up a new application you need an SuperAdmin override to access anything so that they can set up normal admin users.
The next section describes the various approaches used in the AuthP library that come from the above observations.
The following sections describe each part of the Permission Enum.
_NOTE: If you prefer to see the actual Permissions with comments see the Example4Permissions example, which has every part of a AuthP's Permissions Enum.
The code below shows how you would define your Permissions Enum off. The three rules shown in the code are required.
public enum YourPermissions : ushort //1. Must be ushort to work with AuthP
{
NotSet = 0, //2. You mustn't use a zero as a valid member for
// ... other code left out
AccessAll = ushort.MaxValue //3. This allows a user to access every feature
}
NOTE: The AccessAll
Permission member is very powerful and should only be given to a SuperAdmin user. The SuperUser can create normal admin users which have most of the Permission members, but not the AccessAll
Permission.
- The first thing is to group individual parts of a feature into a *Group. See the Sales group
- I define a number for each enum. That's important as if you add a new Enum member in a earlier group.
- I use sequential numbers because I don't want to duplicate a number somewhere else.
- I leave a gap in the numbers (e.g. start the next group at 20, or 100) to allow for new members to be added to a group
public enum YourPermissions : ushort
{
// ... other code left out
//The Sales group
SalesRead = 10,
SalesSell = 11,
SalesReturn = 12,
//The next group
AnotherPermission = 20,
// ... other code left out
}
NOTE: The Permissions above WON'T display in the admin display. The code above is only to show the grouping and numbering. See next section for the recommended member format.
To provide more information for the admin (a developers) about each Permission member.
NOTE: You must define the GroupName
, but the Name
and Description
are optional.
public enum YourPermissions : ushort
{
// ... other code left out
//The Sales group
[Display(GroupName = "Sales", Name = "Read", Description = "Can read any sales")]
SalesRead = 10,
[Display(GroupName = "Sales", Name = "Sell", Description = "Can sell items from stock")]
SalesSell = 11,
[Display(GroupName = "Sales", Name = "Return", Description = "Can return an item to stock")]
SalesReturn = 12,
// ... other code left out
}
Here is an example of how Permissions are shown to an admin person using AuthRolesAdminService.GetPermissionDisplay
method.
NOTE: The GetPermissionDisplay
can filter by GroupName`.
As stated at the start you need a way to obsolete a Permission member. Of course, is to add the [Obsolete]
attribute - see code below.
//----------------------------------------------------
//This is an example of what to do with permission you don't used anymore.
//You don't want its number to be reused as it could cause problems
//Just mark it as obsolete and the PermissionDisplay code won't show it
[Obsolete]
[Display(GroupName = "Old", Name = "Not used", Description = "example of old permission")]
OldPermissionNotUsed = 1_000,
This means it won't display in the admin Permissions display, and all uses of obsoleted Permission member will have a intellisense message saying its obsolete.
Sometimes you want to add new Permission members, but they shouldn't be used by anyone yet. If you don't add a [Display]
attribute it won't be shown the PermissionDisplay.
// A enum member with no <see cref="DisplayAttribute"/> can be used, but won't shown in the PermissionDisplay
// Useful if are working on new permissions but you don't want it to be used by anyone yet
HiddenPermission = 2_000,
NOTE: You can use hidden Permission members in unit tests, including in the bulk loading of Roles, but you can't add a hidden Permission member to an existing application using the normal AuthP admin tools.
Advanced Permissions are permissions where the [Display]
attribute contains AutoGenerateFilter = true
and are used in multi-tenant systems to define a permission should NOT be available to a multi-tenant user. For instance, the ability to create, update or delete a Role would all be an advanced Permission, as tenant users aren't allowed to change Roles as Roles are used across all the tenants.
When an admin user (or bulk load) creates or changes a Role it will set the Role's RoleType
to HiddenFromTenant
if any of the permission in that role is an advanced Permission. NOTE: The admin user can manually set the Role's RoleType
to HiddenFromTenant
too.
The code below shows a permission with the AutoGenerateFilter = true
set in the [Display]
attribute.
[Display(GroupName = "TenantAdmin", Name = "Alter existing Tenants",
Description = "Can update or move a Tenant", AutoGenerateFilter = true)]
TenantUpdate = 42_001,
- Intro to multi-tenants (ASP.NET video)
- Articles in date order:
- 0. Improved Roles/Permissions
- 1. Setting up the database
- 2. Admin: adding users and tenants
- 3. Versioning your app
- 4. Hierarchical multi-tenant
- 5. Advanced technique with claims
- 6. Sharding multi-tenant setup
- 7. Three ways to add new users
- 8. The design of the sharding data
- 9. Down for maintenance article
- 10: Three ways to refresh claims
- 11. Features of Multilingual service
- 12. Custom databases - Part1
- Videos (old)
- Authentication explained
- Permissions explained
- Roles explained
- AuthUser explained
- Multi tenant explained
- Sharding explained
- How AuthP handles sharding
- How AuthP handles errors
- Languages & cultures explained
- JWT Token refresh explained
- Setup Permissions
- Setup Authentication
- Startup code
- Setup the custom database feature
- JWT Token configuration
- Multi tenant configuration
- Using Permissions
- Using JWT Tokens
- Creating a multi-tenant app
- Supporting multiple languages
- Unit Test your AuthP app