This repository has been archived by the owner on Sep 25, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Реализована документация для паттерна реализации доступов
feat: Реализована документация для паттерна реализации доступов
- Loading branch information
Showing
14 changed files
with
1,578 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
--- | ||
sidebar_position: 10 | ||
--- | ||
|
||
# 2FA (Two-factor Auth) | ||
|
||
Permissions могут работать сообща с `2FAService`. | ||
|
||
## Пример | ||
|
||
**Требования** | ||
|
||
Создание документа доступно только администратору с активной 2FA. | ||
|
||
**Реализация** | ||
|
||
```modules/permissions/domain/stores/PermissionsStore/policies/AdministrationPolicyStore``` | ||
```ts | ||
export class AdministrationPolicyStore { | ||
constructor( | ||
private readonly policyManager: PolicyManagerStore, | ||
private readonly userRepo: UserRepository, | ||
private readonly twoFA: TwoFAService, | ||
) { | ||
makeAutoObservable(this, {}, { autoBind: true }); | ||
|
||
this.policyManager.registerPolicy({ | ||
name: 'administration', | ||
prepareData: async (): Promise<void> => { | ||
await Promise.all([this.userRepo.getRolesQuery().async()]); | ||
}, | ||
}); | ||
} | ||
|
||
/** | ||
* Доступ к действиям администратора | ||
*/ | ||
public get administrationActions() { | ||
return this.policyManager.processPermission((allow, deny) => { | ||
// Если twoFA не пройдена, то отказываем в доступе с причиной, которая будет обработана в features | ||
// Также, по необходимости, можно вызвать логику запроса от пользователя прохождения 2FA | ||
if (!twoFA.isPassed) { | ||
return deny(PermissionDenialReason.TwoFA); | ||
} | ||
|
||
if (this.userRepo.getRolesQuery().data?.isAdmin) { | ||
return allow(); | ||
} | ||
|
||
deny(PermissionDenialReason.NoAdmin); | ||
}); | ||
} | ||
} | ||
``` | ||
|
||
```modules/layout/features/MainLayout/Sidebar/UIStore``` | ||
```ts | ||
export class UIStore { | ||
constructor( | ||
private readonly permissions: PermissionsStore, | ||
private readonly twoFA: TwoFAService, | ||
private readonly notifyService: Notify, | ||
private readonly router: Router, | ||
) { | ||
makeAutoObservable(this, {}, { autoBind: true }); | ||
} | ||
|
||
public openDocCreation = () => { | ||
const permission = this.permissions.administration.administrationActions; | ||
|
||
if (permission.isAllowed) { | ||
this.router.push(APP_ROUTES.createDoc.getRedirectPath()); | ||
|
||
return; | ||
} | ||
|
||
if (permission.hasReason('no-admin')) { | ||
this.notifyService.error( | ||
'Доступно только администратору' | ||
); | ||
|
||
return; | ||
} | ||
|
||
if (permission.hasReason('2fa')) { | ||
// Здесь можно, например, реализовать открытие модалки для 2FA | ||
this.notifyService.error( | ||
'Нужно пройти 2FA', | ||
); | ||
|
||
return; | ||
} | ||
|
||
this.notifyService.error( | ||
'Добавить документ на полку нельзя. Попробуйте сменить аккаунт', | ||
); | ||
}; | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"label": "Разграничение доступов (permissions)", | ||
"position": 1, | ||
"link": { | ||
"type": "generated-index", | ||
"description": "Паттерн реализации системы доступов на клиенте" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
--- | ||
sidebar_position: 1 | ||
--- | ||
|
||
# Вдохновлено ABAC и XAML | ||
|
||
Описанный паттерн берет за основу принципы ABAC (Attribute-Based Access Control) и [XAML](https://habr.com/ru/companies/custis/articles/258861/). | ||
|
||
## На клиенте нужен ABAC, даже если на бэкенде RBAC | ||
|
||
В [этой статье](https://habr.com/ru/companies/custis/articles/248649/) вы можете прочитать чем концептуально отличаются ABAC (Attribute-Based Access Control) и RBAC (Role Based Access Control). | ||
|
||
На Frontend'е нужна такая система доступов, которая однозначно будет указывать на предмет блокировок доступов в контексте пользовательского интерфейса. | ||
RBAC и даже ABAC, имплементированный на стороне API не будет зависеть от UI, который привносит свою дополнительную специфичность при расчете доступов. | ||
|
||
В связи с этим, на клиенте необходимо перманентно использовать ABAC, доступы которого будут напрямую связаны со специфичностью UI. | ||
|
||
### Пример с RBAC на бэкенде | ||
|
||
**Предметная область** | ||
|
||
ЭДО | ||
|
||
**Роли** | ||
|
||
- PaymentAccount | ||
- FreeAccount | ||
|
||
**Бизнес требование** | ||
|
||
Кнопка "Создать документ" доступна для пользователя с платным аккаунтом и если у него есть созданная организация. | ||
|
||
**Проблема** | ||
|
||
Из требования видно, что для вычисления доступа не хватает только одного знания о роле пользователя (роль `PaymentAccount`), необходимо дополнительно учитывать есть у пользователя организация. | ||
|
||
**Неверное решение** | ||
|
||
Добавить к кнопке дополнительный `if` на проверку организации. | ||
Это приведет к "размазыванию" логики доступов по приложению и последующую потерю контроля. | ||
|
||
**Правильное решение** | ||
|
||
Использование ABAC с permission `docActions`, который внутри будет проверять роль пользователя и наличие организации. | ||
`docActions` будет использоваться в необходимых частях приложения для проверки доступа к действиям на документом. | ||
|
||
### Пример с ABAC на бэкенде | ||
|
||
**Предметная область** | ||
|
||
ЭДО | ||
|
||
**Permissions с API** | ||
- docActions | ||
|
||
**Бизнес требование** | ||
|
||
Кнопка "Создать документ" доступна для пользователя с платным аккаунтом и если он прошел двух факторную аутентификацию. | ||
|
||
**Проблема** | ||
|
||
В `docActions` на бэкенде проверяется оплачен ли аккаунт пользователя, но проверку на 2FA можно провести только в runtime при нажатии на саму кнопку. | ||
|
||
**Решение** | ||
|
||
Добавить в едином клиентском сервисе доступов дополнительную логику для `docActions`, которая будет проверять 2FA. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
sidebar_position: 11 | ||
--- | ||
|
||
# Пример реализации доступов | ||
|
||
In Progress |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
--- | ||
sidebar_position: 9 | ||
--- | ||
|
||
# Feature Toggle и Permissions | ||
|
||
Feature Toggle и Permissions - это две разные концепции. | ||
|
||
**Feature Toggle** необходим в большинстве случаев для временного выключения функционала. Фича флаги - это временные условия, которые в будущем должны быть удалены. | ||
Например, после тестирования на фокусной группе или конечной реализации функционала. | ||
|
||
В свою очередь **Permissions** - это постоянные условия системы, которые изменяются редко. Изменения происходит только при изменении бизнес требований. | ||
|
||
**Нельзя смешивать концепции Feature Toggle и Permissions в одной абстракции**, в приложении должно быть два отдельных сервиса. | ||
|
||
## Permissions может использовать Feature Toggle | ||
|
||
Permissions может использовать Feature Toggle только в том случае, если Feature Toggle предоставляет [Permissioning Toggles](https://martinfowler.com/articles/feature-toggles.html#CategoriesOfToggles:~:text=Operations%20person%20happy.-,Permissioning%20Toggles,-turning%20on%20new). | ||
|
||
В противном случае Feature Toggle должен использоваться отдельно от Permissions. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
--- | ||
sidebar_position: 0 | ||
--- | ||
|
||
# Мотивация | ||
|
||
Описанный паттерн позволяет реализовать гибкую систему доступов на стороне клиента. | ||
Паттерн учитывает особенности реализации доступов на клиенте. | ||
|
||
## Необходимо применять когда | ||
|
||
- В системе уже реализована какая-либо система доступов без централизованного управления на клиенте | ||
- API предоставляет сведения о ролях. Паттерн работает в связке с ролевой моделью | ||
- API предоставляет сведения о доступах. Паттерн расширяет на клиенте доступы, полученные из API | ||
- На клиенте необходимо по условию (любому) закрывать доступ к части функционала | ||
- Бизнес-требования описывают доступность функционала при определенных условиях (роль, сведения об оплате...) | ||
|
||
## Применение паттерна позволяет | ||
|
||
- Уменьшить затраты на разработку системы доступов | ||
- Иметь единую реализацию системы доступов во всех приложениях компании | ||
- Централизованно развивать паттерн | ||
- Избежать повторения одних и тех же ошибок реализации в разных приложениях | ||
|
||
## Паттерн предоставляет | ||
|
||
- Удобный и поддерживаемый способ формирования доступов на клиенте | ||
- Систему причин отказа в доступе. Позволяет улучшить UX и DX при работе с доступами: пользователь и разработчик получают конкретную причину отказа в доступе | ||
- Подход загрузки данных для формирования доступов | ||
- Закрытие рутов приложения (RouteGuards) | ||
- Взаимодействие с другими сервисами. Например, FeatureToggle |
Oops, something went wrong.