Пользовательская библиотека для реализации контроля доступа на основе разрешений/атрибутов (ABAC) с токенами JSON Web с использованием контроля доступа на основе политики ASP.NET Core (PBAC).
Создайте перечисление разрешений:
public enum Permissions
{
Create = 0 ,
Read = 1 ,
Update = 2 ,
Delete = 3 ,
}Обратите внимание, что наличие точного базового значения для каждого разрешения важно - испортить его, испортит хранимые разрешения!
Кроме того, в настоящее время поддерживаются только перечисление с int в качестве базового типа (по умолчанию).
Установите значения разрешения пользователя внутри вашего поставщика идентификаторов, используя PermissionSet :
user . Claims [ ClaimNames . Permissions ] = new PermissionSet < Permissions > ( new [ ]
{
Permissions . Create ,
Permissions . Read ,
} )
. ToCompactString ( ) ;Добавьте обработчик требований политики разрешения с тем же именем претензии, что и выше:
services . AddPermissionBasedAuthorization < Permissions > ( options =>
options . PermissionsClaimName = ClaimNames . Permissions ) ; Обратите внимание, что если вы повторно определите авторизацию DefaultPolicy в вашем приложении, то после вашей логики должен быть вставлен код, приведенный выше, чтобы унаследовать политику разрешений унаследовать новую политику по умолчанию.
(Необязательно) наследуйте AuthorizePermission<T> с конкретным типом перечисления разрешений:
public class AuthorizePermissionAttribute : AuthorizePermissionAttribute < Permissions >
{
public AuthorizePermissionAttribute ( Permissions permission )
: base ( permission )
{ }
}Или создайте метод расширения при использовании минимальных API:
public static TBuilder RequirePermission < TBuilder > ( this TBuilder builder , Permissions permission )
where TBuilder : IEndpointConventionBuilder
{
if ( builder == null )
throw new ArgumentNullException ( nameof ( builder ) ) ;
return builder . RequireAuthorization ( new AuthorizePermissionAttribute < Permissions > ( permission ) ) ;
} Украсить контроллеры/конечные точки атрибутом AuthorizePermission<T> (или созданным выше):
[ HttpGet ]
[ Authorize ( Permissions . Read ) ]
public IActionResult Get ( )
=> Ok ( ) ;Или при использовании минимальных API:
app . MapGet ( "/" , ( ) => Results . Ok ( ) )
. RequirePermission ( Permissions . Read ) ; Набор разрешений сериализуется в строку в виде шестнадцатеричного числа, где n -й бит представляет наличие разрешения с базовым значением n .
Например, рассмотрим следующее разрешение перечисления:
public enum Permissions
{
Create = 0,
Read = 1,
Update = 2,
Delete = 3,
Manage = 4,
}
Затем двоичное представление набора, содержащего все разрешения выше, будет выглядеть так:
1 F - permission string
┌┬┬┤ ┌┬┬┤
0001 1111 - permission bit values
││││ ││││
7654 3210 - bit positions
└┬┘│ ││││
│ │ │││└ Create
│ │ ││└ Read
│ │ │└ Update
│ │ └ Delete
│ └ Manage
└ Not used
Для десериализации приведенное выше делается в обратном порядке.
Кроме того, поскольку, основываясь на значении перечисления, мы можем рассчитать определенную позицию бита, которую мы должны проверить, нам не нужно десериализировать всю строку, когда мы проверяем одно разрешение.
Проверка единого значения разрешения из компактной строки:
| Метод | Иметь в виду | Ошибка | Stddev | Выделено |
|---|---|---|---|---|
| PermissionSet_haspermission | 74,17 нс | 1,382 нс | 1,225 нс | - |
Утверждение пользователя имеет необходимое разрешение в их списке претензий:
| Метод | Иметь в виду | Ошибка | Stddev | Выделено |
|---|---|---|---|---|
| Разрешение OuthorizationHandlerBenchmark_HandLEREQUIREMENTASYNC | 359,4 нс | 6,79 нс | 13,25 нс | 144 б |