@via-profit/ability 2.0.0-rc.8 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,109 +3,92 @@
3
3
  > Набор сервисов, частично реализующих
4
4
  > принцип [Attribute Based Access Control](https://en.wikipedia.org/wiki/Attribute-based_access_control)
5
5
 
6
- Данный сервис позволяет создать правила или политики, а затем применить их по отношению к каким-либо данным для того
7
- чтобы проверить наличие доступа к этим данным.
8
-
9
- # Draft
6
+ Этот сервис позволяет создавать правила и политики, применять их к данным и проверять доступ на их основе.
10
7
 
11
8
  ## Содержание
12
9
 
13
- 1. [Описание и общие принципы](#overview)
14
-
15
- 1.1 [Состав пакета](#structure)
16
-
17
- 1.2 [Общие принципы](#principles)
18
-
19
- 2. [Правила](#rules)
20
-
21
- 2.1 [Синтаксис правил](#rule-syntax)
22
-
23
- 2.2 [Примеры](#rule-recipes)
10
+ ## Оглавление
11
+ - [Обзор](#overview)
12
+ - [Состав пакета](#structure)
13
+ - [Основные принципы](#principles)
14
+ - [Правила](#rules)
15
+ - [Создание правила](#rule-creation)
16
+ - [Проверка правила](#rule-check)
17
+ - [Группы правил](#rule-sets)
18
+ - [Создание группы правил](#ruleset-creation)
19
+ - [Проверка группы правил](#ruleset-check)
20
+ - [Политики](#policies)
21
+ - [Создание политики](#policy-creattion)
22
+ - [Проверка политики](#policy-check)
23
+ - [Управление политиками](#policy-management)
24
24
 
25
- 2.3 [Класс AbilityRule](#ability-rule-class)
26
25
 
27
- 3. [Политики](#policies)
26
+ ---
28
27
 
29
- 3.1 [Синтаксис правил](#policy-syntax)
30
-
31
- 3.2 [Примеры](#policy-recipes)
32
-
33
- 3.3 [Класс AbilityPolicy](#ability-policy-class)
34
-
35
- 4. [Создание политики из конфига](#policy-config)
36
-
37
- ## Описание и общие принципы <a name="overview"></a>
28
+ ## Обзор <a name="overview"></a>
38
29
 
39
30
  ### Состав пакета <a name="structure"></a>
40
31
 
41
- - `AbilityPolicy` - класс политики
42
- - `AbilityRuleSet` - класс группы правил
43
- - `AbilityRule` - класс правила
44
- - `AbilityParser` - парсер конфигурационных правил из/в JSON
45
- - `AbilityResolver` - класс управления политиками
46
- - `AbilityMatch` - Класс констант для определния соответствия правил (`PENDING` `MATCH` `MISMATCH`)
47
- - `AbilityPolicyEffect` - Класс констант для определния эффекта политик (`DENY` `PERMIT`)
48
- - `AbilityCompare` - Класс констант для определния способа сравнения правил и групп (`OR` `AND`)
49
- - `AbilityCondition` - Класс констант для определния метода вычисления правил (`EQUAL` `NOT_EQUAL` `MORE_THAN`
50
- `LESS_THAN` `LESS_OR_EQUAL` `MORE_OR_EQUAL` `IN` `NOT_IN`)
51
- - `AbilityError` - Класс инстанса ошибки
52
- - `AbilityCode` - Базовый клас констанкт
32
+ - **`AbilityRule`** класс отдельного правила
33
+ - **`AbilityRuleSet`** класс группы правил
34
+ - **`AbilityPolicy`** класс политики
35
+ - **`AbilityResolver`** управление политиками
36
+ - **`AbilityMatch`** константы состояния правил (`pending`, `match`, `mismatch`)
37
+ - **`AbilityCompare`** способы сравнения (`or`, `and`)
38
+ - **`AbilityCondition`** методы вычисления (`equal`, `not_equal`, `more_than`, `less_than`, `in`, `not_in` и др.)
39
+ - **`AbilityPolicyEffect`** эффекты политики (`deny`, `permit`)
40
+ - **`AbilityParser`** парсер конфигурационных правил (JSON)
41
+ - **`AbilityError`** инстанс ошибок
42
+
43
+ ### Основные принципы <a name="principles"></a>
53
44
 
54
- ### Общие принципы <a name="principles"></a>
45
+ Работа сервиса основана на формировании **правил**, объединении их в **политики** и проверке доступа с их помощью.
55
46
 
56
- Принцип работы основан на формировании правил, объединения их в политики и запуске этих политик.
47
+ Пример: необходимо **запретить доступ** пользователям, связанным с отделом менеджеров, **за исключением администраторов**.
57
48
 
58
- Предположим, что необходимо запретить доступ пользователям из отдела менеджеров и причастным к ним, за исключением
59
- администраторов. Пользователи относятся к отделу менеджеров, если их отдел называется `managers`. Причастные
60
- пользователи являются те пользователи, среди ролей которых имеется роль `manager`. Администраторы - пользователи имеющие
61
- соответствующую роль (`administrator`).
49
+ - Менеджеры если их отдел `managers` или есть роль `manager`
50
+ - Администраторы пользователи с ролью `administrator`
62
51
 
63
- Для решения поставленной задачи нам понадобится объединить несколько правил в группы согласно изображению ниже:
52
+ Структура политики:
64
53
 
65
54
  ![ability-01.drawio.png](assets/ability-01.drawio.png)
66
55
 
67
- JSON представление такой политики будет иметь следующий вид:
56
+ JSON-конфигурация:
68
57
 
69
58
  ```json
70
59
  {
71
- "name": "Запретить доступ пользователям из отдела менеджеров и причастным к ним за исключением администраторов",
72
- "compareMethod": 1,
60
+ "name": "Запрет доступа для менеджеров (исключение: администраторы)",
61
+ "compareMethod": "and",
73
62
  "action": "order.update",
74
- "effect": 0,
63
+ "effect": "deny",
75
64
  "ruleSet": [
76
65
  {
77
66
  "name": "Менеджеры",
78
- "compareMethod": 0,
67
+ "compareMethod": "or",
79
68
  "rules": [
80
69
  {
81
- "name": "Пользователь состоит в отделе managers",
82
- "matches": [
83
- "user.department",
84
- "=",
85
- "managers"
86
- ]
70
+ "name": "Отдел managers",
71
+ "subject": "user.department",
72
+ "resource": "managers",
73
+ "condition": "in"
87
74
  },
88
75
  {
89
- "name": "Пользователь имеет роль manager",
90
- "matches": [
91
- "user.roles",
92
- "in",
93
- "manager"
94
- ]
76
+ "name": "Роль manager",
77
+ "subject": "user.roles",
78
+ "resource": "manager",
79
+ "condition": "in"
95
80
  }
96
81
  ]
97
82
  },
98
83
  {
99
84
  "name": "Не администраторы",
100
- "compareMethod": 1,
85
+ "compareMethod": "and",
101
86
  "rules": [
102
87
  {
103
- "name": "Пользователь не является администратором",
104
- "matches": [
105
- "user.roles",
106
- "not in",
107
- "administrator"
108
- ]
88
+ "name": "Нет роли administrator",
89
+ "subject": "user.roles",
90
+ "resource": "administrator",
91
+ "condition": "not in"
109
92
  }
110
93
  ]
111
94
  }
@@ -113,154 +96,343 @@ JSON представление такой политики будет имет
113
96
  }
114
97
  ```
115
98
 
116
- Теперь для того чтобы применить (проверить политику) необходимо её восстановить из JSON (метод `parse`) и запустить
117
- проверку (метод `check`):
99
+ Применение политики:
118
100
 
119
101
  ```ts
120
- const jsonConfig = { ... }
121
-
122
- const result = AbilityPolicy.parse(jsonConfig).check({
102
+ const jsonConfig = { ... };
103
+ AbilityPolicy.parse(jsonConfig).check({
123
104
  user: {
124
105
  department: 'managers',
125
- roles: ['manager', 'couch']
106
+ roles: ['manager', 'coach'],
126
107
  }
127
108
  });
128
- ````
109
+ ```
110
+
111
+ ---
129
112
 
130
113
  ## Правила <a name="rules"></a>
131
114
 
132
- Правила позволяют создавать условия, которые в последствии будут сгруппированы в группу правил, а те, в свою очередь, в
133
- политику.
115
+ **Правила** выполняют условие проверки и возвращают результат. **Основная цель** - выполнить сравнение переданных
116
+ значений субъекта и ресурса, а затем вернуть результат такого сравнения.
117
+
118
+ ### Создание правила <a name="rule-creation"></a>
134
119
 
135
- Класс `AbilityRule`
120
+ Создать правило можно двумя способами: создание через конструктор класса и парсинг JSON-конфига правила.
136
121
 
137
- Правило определяется необязательных названием и обязательным массивом `matches`, который и несёт самую важную роль в
138
- данном модуле.
122
+ При создании необходимо указать следующие параметры:
139
123
 
140
- _Пример простого правила:_
124
+ - **id** - `string` Уникальный идентификатор.
125
+ - **name** - `string` Название правила.
126
+ - **condition** - `AbilityCondition` Определяет условия сравнения переданных данных
127
+ - **subject** - `string` Dot notation путь в проверяемом субъекте, например: `user.name`.
128
+ - **resource** - `string | number | boolean | (string | number)[]` Dot notation путь в проверяемом ресурсе, например:
129
+ `user.name` или значение, которое может быть строкой, числом, булеан значением или массивом строк или чисел.
130
+
131
+ _Создание правила через конструктор класса:_
141
132
 
142
133
  ```ts
143
134
  import { AbilityRule, AbilityCondition } from '@via-profit/ability';
144
135
 
145
136
  const rule = new AbilityRule({
146
- name: 'Simple rule',
147
- matches: [
148
- 'user.department', // dot notation путь до проверяемого поля
149
- AbilityCondition.EQUAL, // определяет метод сравнения "="
150
- 'managers' // искомое значение
151
- ],
137
+ id: '<rule-id>',
138
+ name: 'Пользователь из отдела managers',
139
+ subject: 'user.department',
140
+ resource: 'managers',
141
+ condition: AbilityCondition.equal
152
142
  });
153
143
 
154
144
  ```
155
145
 
156
- Правило выше будет выполнено в случае, если среди проверямых данных будет ключ `user`, содержащий ключ `department`,
157
- значение которого будет равно (`=`) `managers`
146
+ _Создание правила через парсинг JSON-конфигурации:_
158
147
 
159
- Адрес поля `user.department`, представляет собой запись в
160
- формате [dot notation](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Basics#dot_notation), что
161
- указывает, что для сравнения данных будет использоваться поле department ресурса `user`.
162
- Для сравнения двух отделов будет использоваться оператор сравнения `=`.
148
+ ```ts
149
+ import { AbilityRule } from '@via-profit/ability';
150
+
151
+ const rule = AbilityRule.parse({
152
+ "id": "<rule-id>",
153
+ "name": "Пользователь из отдела managers",
154
+ "subject": "user.department",
155
+ "resource": "managers",
156
+ "condition": "="
157
+ });
163
158
 
164
- Теперь, для того чтобы проверить правило, необходимо выполнить метод `check` передав необходимые ресурсы:
159
+ ```
165
160
 
166
- ```ts
167
- import { AbilityRule, AbilityCondition } from '@via-profit/ability';
161
+ ### Проверка правила <a name="rule-check"></a>
168
162
 
169
- const rule = new AbilityRule({
170
- name: 'Simple rule',
171
- matches: [
172
- 'user.department', // dot notation путь до проверяемого поля
173
- AbilityCondition.EQUAL, // определяет метод сравнения "="
174
- 'managers' // искомое значение
175
- ],
163
+ Для проверки правила следует вызвать метод `check` класса `AbilityRule` передав объект проверяемого ресурса. Этот метод
164
+ вернёт экземпляр класса
165
+ `AbilityMatch`, при помощи методов которого можно определить имеется ли совпадение правила и переданных значений.
166
+
167
+ ```ts
168
+ import { AbilityRule } from '@via-profit/ability';
169
+
170
+ const rule = AbilityRule.parse({
171
+ "id": "<rule-id>",
172
+ "name": "Пользователь из отдела managers",
173
+ "subject": "user.department",
174
+ "resource": "managers",
175
+ "condition": "="
176
176
  });
177
177
 
178
- const result = rule.check({
178
+ const match = rule.check({
179
179
  user: {
180
180
  department: 'managers',
181
- }
181
+ },
182
182
  });
183
183
 
184
+ const is = match.isEqual(AbilityMatch.match); // true
185
+
184
186
  ```
185
187
 
186
- ### Синтаксис правил <a name="rule-syntax"></a>
188
+ ---
189
+
190
+ ## Группы правил <a name="rule-sets"></a>
191
+
192
+ **Группы правил** необходимы для объединения нескольких правил в группу. **Основная цель** - выполнить проверку каждого
193
+ правила в группе и вернуть лишь один результат.
194
+
195
+ Создавая группу следует указывать метод сравнения (`compareMethod`), который необходим для вычисления значения всей
196
+ группы при проверке правил.
197
+
198
+ При создании необходимо указать следующие параметры:
199
+
200
+ - **id** - `string` Уникальный идентификатор.
201
+ - **name** - `string` Название группы.
202
+ - **compareMethod** - `AbilityCompare` Способ сравнения правил в группе (`or` или `and`).
203
+
204
+ _Влияние **compareMethod** на результат вычисления группы:_
205
+
206
+ - **`or`** - Результат всей группы примет значение `match`, если хотя бы одно из правил вернуло `match`.
207
+ - **`and`** - Результат всей группы примет значение `match`, если все правила вернули `match`.
208
+
209
+ ### Создание группы правил <a name="ruleset-creation"></a>
187
210
 
188
- Для описания правил используется массив следующего типа:
211
+ Создать группу правил можно двумя способами: создание через конструктор класса и парсинг JSON-конфига группы.
212
+
213
+ _Создание группы через конструктор класса_:
189
214
 
190
215
  ```ts
191
- type AbilityRuleMatches = [
192
- string, // dot notation путь до поля в субъекте или энвайронменте
193
- '=' | '<>' | '>' | '<' | '<=' | '>=' | 'in', // оператор сравнения
194
- string | number | boolean, // dot notation путь до поля в ресурсе или энвайронменте или просто значение
195
- ];
216
+ import { AbilityRuleSet, AbilityCompare } from '@via-profit/ability';
217
+
218
+ const ruleSet = new AbilityRuleSet({
219
+ id: '<set-id>',
220
+ name: 'Название группы',
221
+ compareMethod: AbilityCompare.and,
222
+ });
223
+
224
+ // Добавление правил в группу
225
+ ruleSet.addRules([
226
+ new AbilityRule(...),
227
+ new AbilityRule(...),
228
+ ]);
229
+
196
230
  ```
197
231
 
198
- ### Операторы сравнения <a name="rule-operators"></a>
232
+ _Создание группы через парсинг JSON-конфига группы_:
233
+
234
+ ```ts
235
+ import { AbilityRuleSet } from '@via-profit/ability';
236
+
237
+ const ruleSet = AbilityRuleSet.parse({
238
+ 'id': '<set-id>',
239
+ 'name': 'Название группы',
240
+ 'compareMethod': 'and',
241
+ 'rules': [
242
+ {
243
+ 'id': '<rule-id>',
244
+ 'name': 'Пользователь из отдела managers',
245
+ 'subject': 'user.department',
246
+ 'resource': 'managers',
247
+ 'condition': '=',
248
+ },
249
+ ],
250
+ });
199
251
 
200
- - `AbilityCondition.EQUAL` (`=`) Прямое сравнение
201
- - `AbilityCondition.NOT_EQUAL` (`<>`) Не равно
202
- - `AbilityCondition.MORE_THAN` (`>`) Больше
203
- - `AbilityCondition.LESS_THAN` (`<`) Меньше
204
- - `AbilityCondition.LESS_OR_EQUAL` (`<=`) Меньше или равно
205
- - `AbilityCondition.MORE_OR_EQUAL` (`>=`) Больше или равно
206
- - `AbilityCondition.IN` (`in` Вхождение в массив. Позволяет проверять вхождение значения в массив
207
- - `AbilityCondition.NOT_IN` (`not in` Нет вхождения в массив. Позволяет проверять отсутствие значения в массив
252
+ ```
208
253
 
209
- ### Примеры правил <a name="rule-recipes"></a>
254
+ ### Проверка группы правил <a name="ruleset-check"></a>
210
255
 
211
- <details>
212
- <summary>Пользователь старше 21 года</summary>
256
+ Для проверки группы правил следует вызвать метод `check` класса `AbilityRuleSet` передав объект проверяемого ресурса.
257
+ Этот метод вернёт экземпляр класса `AbilityMatch`, при помощи методов которого можно определить имеется ли совпадение
258
+ для группы и переданных значений.
213
259
 
214
260
  ```ts
215
- const user = {
216
- age: 18,
217
- };
261
+ import { AbilityRuleSet, AbilityCompare } from '@via-profit/ability';
218
262
 
219
- const isPermit = new AbilityRule('User age', ['subject.age', '>=', 21]).isPermit(user); // true
263
+ const ruleSet = new AbilityRuleSet({
264
+ id: '<set-id>',
265
+ name: 'Название группы',
266
+ compareMethod: AbilityCompare.and,
267
+ }).addRules([
268
+ new AbilityRule(...),
269
+ new AbilityRule(...),
270
+ ]);
271
+
272
+ const match = rule.check({ ... });
273
+
274
+ const is = match.isEqual(AbilityMatch.match);
220
275
  ```
221
276
 
222
- </details>
277
+ ___
278
+
279
+ ## Политики <a name="policies"></a>
280
+
281
+ **Политики** включают в себя группы правил. Основная цель - выполнить проверку всех вложенных групп, сравнить результат
282
+ выполнения групп и вернуть один единственный результат.
283
+
284
+ ### Создание политики <a name="policy-creattion"></a>
285
+
286
+ Создать политику можно двумя способами: создание через конструктор класса и парсинг JSON-конфига политики.
287
+
288
+ При создании политики необходимо указать следующие параметры:
289
+
290
+ - **id** - `string` Уникальный идентификатор.
291
+ - **name** - `string` Название политики.
292
+ - **action** - `string` Ключ политики, в формате Dot notation, определяющий схожесть политик. В названии может
293
+ применяться символ звездочки (`*`). Политики с одинаковым экшеном обрабатываются вместе как группа политик. Экшен
294
+ `users.account` не считается похожим с экшеном `users.account.login`, но в это же время `users.account.*` равен экшену
295
+ `users.account.login` (из-за использования звездочки).
296
+ - **compareMethod** - `AbilityCompare` Метод сравнения групп правил, входящих в политику (`or` или `and`)
297
+ - **effect** - `AbilityPolicyEffect` Определяет итоговый результат всех вычислений (`permit` или `deny`). В слчае
298
+ использования класса `AbilityResolver` (метод `enforce`) последний выкинет исключение `AbilityError`, если политика
299
+ вернёт `deny`. Текст сообщения `AbilityError` будет соответствовать названию сработавшей политики. В остальных случаях
300
+ ничего не произойдет.
301
+ - **ruleSet** - `AbilityRuleSet[]` Массив групп (см. [Группы правил](#rule-sets))
223
302
 
224
- <details>
225
- <summary>Пользователь имеет роль администратора</summary>
303
+ **Замечание** - Политика может быть запрещающей (`effect` = `deny`) и разрешающей (`effect` = `permit`). Если вам
304
+ необходимо ограничить какой-либо доступ, например, пользователю с недостаточными правами, то следует создавать политику
305
+ с эффектом `deny`.
306
+
307
+ _Создание политики через конструктор класса_:
226
308
 
227
309
  ```ts
228
- const user = {
229
- roles: ['administrator', 'manager'],
230
- };
310
+ import { AbilityPolicy, AbilityCondition } from '@via-profit/ability';
311
+
312
+ const policy = new AbilityPolicy({
313
+ id: '<policy-id>',
314
+ name: 'Пример политики',
315
+ effect: 'deny',
316
+ action: 'users.update',
317
+ compareMethod: 'and',
318
+ ruleSet: [
319
+ new AbilityRule({
320
+ id: '<rule-id>',
321
+ name: 'Пользователь является владельцем заказа',
322
+ subject: 'user.id',
323
+ resource: 'order.owner',
324
+ condition: AbilityCondition.equal
325
+ })
326
+ ]
327
+ });
231
328
 
232
- const isPermit = new AbilityRule('has role', ['subject.roles', 'in', 'administrator']).isPermit(
233
- user,
234
- ); // true
235
329
  ```
236
330
 
237
- </details>
331
+ _Создание политики через парсинг JSON-конфига_:
238
332
 
239
- <details>
240
- <summary>Пользователь является владельцем заказа</summary>
333
+ ```ts
334
+ import { AbilityPolicy } from '@via-profit/ability';
335
+
336
+ const policy = AbilityPolicy.parse({
337
+ "id": "bb758c1b-1015-4894-ba25-d23156e063cf",
338
+ "name": "Status hui",
339
+ "action": "order.status",
340
+ "effect": "deny",
341
+ "compareMethod": "and",
342
+ "ruleSet": [
343
+ {
344
+ "id": "9cc009e5-0aa9-453a-a668-cb3f418ced92",
345
+ "name": "Не администратор",
346
+ "compareMethod": "and",
347
+ "rules": [
348
+ {
349
+ "id": "4093cd50-e54f-4062-8053-2d3b5966fad3",
350
+ "name": "Нет роли администраторв",
351
+ "subject": "account.roles",
352
+ "resource": "administrator",
353
+ "condition": "<>"
354
+ }
355
+ ]
356
+ }
357
+ ]
358
+ });
359
+
360
+ ```
361
+
362
+ ### Проверка политики <a name="policy-check"></a>
363
+
364
+ Для проверки политики правил следует вызвать метод `check` класса `AbilityPolicy` передав объект проверяемого ресурса.
365
+ Этот метод вернёт экземпляр класса `AbilityMatch`, при помощи методов которого можно определить имеется ли совпадение
366
+ для группы и переданных значений.
241
367
 
242
368
  ```ts
243
- const user = {
244
- id: '1',
245
- };
369
+ import { AbilityPolicy } from '@via-profit/ability';
246
370
 
247
- const order = {
248
- owner: '1',
249
- };
371
+ const policy = AbilityPolicy.parse({ ... });
372
+
373
+ const match = policy.check({ ... });
250
374
 
251
- const isPermit = new AbilityRule('owner', ['subject.id', '=', 'resource.owner']).isPermit(
252
- user,
253
- order,
254
- ); // true
375
+ const is = match.isEqual(AbilityMatch.match);
255
376
  ```
256
377
 
257
- </details>
378
+ ___
258
379
 
259
- ## Политики <a name="policies"></a>
380
+ ## Управление политиками <a name="policy-management"></a>
381
+
382
+ Для управления политиками реализован специальный класс `AbilityResolver`.
383
+
384
+ В случае, если вам необходимо запустить лишь разовую проверку данных, то данный раздел можно опустить.
260
385
 
261
- Политики позволяют группировать правила или создавать вложенные друг в друга политики.
386
+ **AbilityResolver** необходим для возможности запуска проверки разных политик в разный период времени.
262
387
 
388
+ Политики содержат название экшена (поле `action`) определяемого разработчиком. Запуск метода `enforce` или `resolve`
389
+ отберет из всех переданных политик только те, которые попадают под указанный экшен.
390
+
391
+ ```ts
392
+ import { AbilityPolicy, AbilityPolicyConfig, AbilityResolver } from './AbilityPolicy';
393
+
394
+ const config: AbilityPolicyConfig[] = [...]; // массив различных политик (JSON)
395
+ const policies: AbilityPolicy<Resources>[] = config.map(cfg => AbilityPolicy.parse(cfg)); // массив уже созданных политик
396
+
397
+ // Проверка политик с экшеном `order.create`
398
+ // Варинат 1. Будет выброшено исключение AbilityError
399
+ // c название политики, которая вернула deny,
400
+ // либо ничего не произойдет, если ни одна из политик
401
+ // не вернет deny
402
+ new AbilityResolver(policies).enforce('order.create', {
403
+ user: { department: 'managers' },
404
+ });
405
+
406
+ // Вариант 2.
407
+ const isDeny = new AbilityResolver(policies)
408
+ .resolve('order.create', {
409
+ user: { department: 'managers' },
410
+ })
411
+ .isDeny();
412
+
413
+ if (isDeny) {
414
+ throw new AbilityError('Permission denied');
415
+ }
416
+
417
+
418
+ // Типы ресурсов, где каждый ключ будет являться название экшена
419
+ type Resources = {
420
+ ['order.status']: { // <-- название экшена
421
+ readonly account: { // <-- данные ресурса
422
+ readonly roles: readonly string[];
423
+ };
424
+ };
425
+ ['order.create']: {
426
+ readonly user: {
427
+ readonly department: string;
428
+ };
429
+ };
430
+ ...
431
+ };
432
+
433
+ ```
263
434
 
264
- ## Создание политики из конфига <a name="policy-config"></a>
435
+ _Пояснение примера выше. В данном примере создается массив всех политик, а затем запускается проверка политик подходящих
436
+ по указанному экшену, а самое главное, что при помощи типа `Resources`, который необходимо формировать
437
+ вручную, **TypeScript** подскажет какие именно данные следует передать вторым аргументом (ресурс)._
265
438
 
266
- Политику и правила можно создавать не только по средствам классов, но и при помощи конфигураций.