Остання зміна 2024/07/11 10:07 автором Ashterix

Сховати останніх авторів
Ashterix 23.1 1 {{box cssClass="floatinginfobox" title="**Зміст**"}}
2 {{toc/}}
3 {{/box}}
Ashterix 2.1 4
Ashterix 25.1 5 {{error}}
6 **УВАГА!!! **Ця версія документації застаріла.
7
8 В JsonRpcBundle версії 7 конфігурація зазнала суттєвих змін і не має зворотної сумісності з версією 6.
9 {{/error}}
10
Ashterix 2.1 11 (% class="wikigeneratedid" %)
Ashterix 23.1 12 Всі налаштування бандла знаходяться в файлі {{code language="none"}}config/packages/ufo_json_rpc.yaml{{/code}}.
Ashterix 2.1 13
14 (% class="wikigeneratedid" %)
15 Є можливість налаштувати параметри захисту API та деякі параметри формату даних, що віддається при запиті документації.
16
Ashterix 23.1 17 = Блок {{code language="none"}}security{{/code}} =
Ashterix 2.1 18
19 Наразі єдиним механізмом захисту доступу до вашого API є встановлення перевірки ключа доступу (api_token).
20
Ashterix 23.1 21 == Параметр {{code language="none"}}protected_methods{{/code}} ==
Ashterix 2.1 22
23 (% class="wikigeneratedid" %)
24 Цей параметр приймає масив назв http методів, які мають бути захищені.
25
26 (% class="wikigeneratedid" %)
27 За замовченням ввімкнут захист лише для методу POST. Ви можете:
28
Ashterix 23.1 29 * вказати пустий масив {{code language="none"}}[]{{/code}} щоб зробити API повністю відкритим
Ashterix 2.1 30
Ashterix 23.1 31 {{code language="yaml" layout="LINENUMBERS" title="config/packages/ufo_json_rpc.yaml"}}
32 ufo_json_rpc:
33 security:
34 protected_methods: []
35 {{/code}}
Ashterix 2.1 36
37 * вказати додатково захист для методу GET, що зробить запит документації недоступним без токену в заголовках запиту
38
Ashterix 23.1 39 {{code language="yaml" layout="LINENUMBERS" title="config/packages/ufo_json_rpc.yaml"}}
40 ufo_json_rpc:
41 security:
42 protected_methods: ['GET', 'POST']
43 {{/code}}
Ashterix 2.1 44
Ashterix 23.1 45 (% id="cke_bm_164641S" style="display:none" %) (%%)Якщо ви захищаєте ваш API через {{code language="none"}}protected_methods{{/code}}, вам необхідно налаштувати токени, по яким буде відкритий доступ.
Ashterix 2.1 46
47 Перш за все, треба визначитися з назвою токену.
48
Ashterix 23.1 49 == Параметр {{code language="none"}}token_key_in_header{{/code}} ==
Ashterix 2.1 50
Ashterix 23.1 51 Компонент {{code language="none"}}RpcSecurity{{/code}} буде шукати в заголовках запиту специфічний ключ, який ви можете встановити в налаштуваннях пакету, значення за замовченням {{code language="none"}}token_key_in_header: 'Ufo-RPC-Token'{{/code}}, ви можете встановити будь-яке інше значення яке відповідає наступним вимогам.
Ashterix 2.1 52
Ashterix 23.1 53 {{spoiler title=" Вимоги до формування заголовків протоколу HTTP"}}
Ashterix 5.1 54 Вимоги до назв заголовків HTTP не є строго регульованими щодо капіталізації, оскільки HTTP заголовки нечутливі до регістру. Однак, існують деякі загальні практики і стандарти, які зазвичай дотримуються для кращої читабельності та узгодженості:
Ashterix 2.1 55
Ashterix 5.2 56 - Капіталізація: Зазвичай назви HTTP заголовків пишуться з використанням CamelCase, де кожне слово починається з великої літери, наприклад, Content-Type, User-Agent, Accept-Encoding. Це не впливає на технічну обробку заголовків, але робить їх легше читати.
57 - Унікальність: Кожен заголовок повинен мати унікальну назву у контексті одного HTTP запиту або відповіді. Не можна використовувати однакові назви для різних заголовків у тому самому запиті чи відповіді.
58 - Спеціальні заголовки: Існують заголовки, які використовуються специфічно для контролю поведінки кешування (Cache-Control), безпеки (Strict-Transport-Security), аутентифікації (Authorization), тощо.
59 - Норми RFC: Вимоги до заголовків регулюються документами RFC, які визначають стандарти для протоколів Інтернету. Наприклад, загальні заголовки і їхнє використання описані в RFC 7231.
Ashterix 23.1 60 {{/spoiler}}
Ashterix 2.1 61
Ashterix 18.1 62
Ashterix 21.2 63
64
Ashterix 24.1 65
Ashterix 25.1 66
67
Ashterix 23.1 68 == Параметр {{code language="none"}}clients_tokens{{/code}} ==
Ashterix 2.1 69
Ashterix 5.2 70 Тепер слід вказати масив клієнтськіх токенів, які будуть мати доступ до API.
Ashterix 2.2 71
Ashterix 5.2 72 Тут є певна варіативність.
Ashterix 2.2 73
Ashterix 5.2 74 === Токени в параметрах ===
Ashterix 4.1 75
Ashterix 5.2 76 (% class="box errormessage" %)
77 (((
78 **НЕ РЕКОМЕНДОВАНО!!!**
79 \\Цей підхід допускається лише для локального тестування API
80 )))
Ashterix 4.1 81
Ashterix 5.2 82 Є можливість прописати токени хардкодом прямо в файлі налаштувань.
Ashterix 5.1 83
Ashterix 5.2 84 Це погано з позиції безпеки, якщо код зберігається в публічному репозиторію, то до цього токену буде мати доступ кожен.
Ashterix 5.1 85
Ashterix 23.1 86 {{code language="yaml" layout="LINENUMBERS" title="config/packages/ufo_json_rpc.yaml"}}
87 ufo_json_rpc:
88 security:
89 protected_methods: ['GET', 'POST']
90 token_key_in_header: 'Ufo-RPC-Token'
91 clients_tokens:
92 - 'ClientTokenExample' # hardcoded token example. Importantly!!! Replace or delete it!
Ashterix 5.3 93
Ashterix 23.1 94 {{/code}}
Ashterix 5.1 95
Ashterix 5.2 96 === Токени в змінних оточення ===
Ashterix 5.1 97
Ashterix 5.2 98 Це найбільш доцільний механізм у разі, якщо ви розробляєте сервіс для розподіленого бекенду, що написаний на SOA (Сервіс-Орієнтована Архітектура). Зазвичай, в такому випадку, вам треба відкрити доступ до апі одному або обмеженій кількості клієнтських додатків і оновлення ключів не буде відбуватися занадто часто.
Ashterix 5.1 99
Ashterix 23.1 100 В такому випадку можна прописати токени в змінних оточення (файл {{code language="none"}}.env.local{{/code}} під час локальної розробки). Цей механізм достатньо безпечний з боку збереження доступів.
Ashterix 5.1 101
Ashterix 6.1 102 (((
Ashterix 23.1 103 {{code language="ini" layout="LINENUMBERS" title=".env.local"}}
104 TOKEN_FOR_APP_1=9363074966579432364f8b73b3318f71
105 TOKEN_FOR_APP_2=456fg87g8h98jmnb8675r4445n8up365
106 {{/code}}
Ashterix 6.1 107
Ashterix 23.1 108 {{code language="yaml" layout="LINENUMBERS" title="config/packages/ufo_json_rpc.yaml"}}
109 ufo_json_rpc:
110 security:
111 protected_methods: ['GET', 'POST']
112 token_key_in_header: 'Ufo-RPC-Token'
113 clients_tokens:
114 - '%env(resolve:TOKEN_FOR_APP_1)%' # token example from .env.local
115 - '%env(resolve:TOKEN_FOR_APP_2)%' # token example from .env.local
116 {{/code}}
Ashterix 6.1 117 )))
Ashterix 12.2 118
119 === Токени для користувача ===
120
Ashterix 13.3 121 Припускаю, що у вас може виникнути потреба зробити персональні ключі для користувачів вашого додатку, можливо ви захочете впровадити ліміти або інші обмеження.
Ashterix 14.1 122 В такому випадку вам не потрібно вказувати перелік токенів в конфігах, ви можете зберігати їх в базі даних або іншому місці згідно вашій бізнес-логіки. Єдина вимога, у вас має бути сервіс, який вміє перевіряти чи існує наданий токен.
Ashterix 13.1 123
Ashterix 23.1 124 Для того, щоб JsonRpcServer міг використовувати вашу логіку, доведеться реалізувати власний клас, що реалізує інтерфейс {{code language="none"}}Ufo\JsonRpcBundle\Security\Interfaces\ITokenValidator{{/code}}
Ashterix 13.3 125
Ashterix 23.1 126 {{code language="php" layout="LINENUMBERS" title="==== Приклад власного валідатора токенів ===="}}
127 <?php
Ashterix 13.1 128
Ashterix 23.1 129 namespace App\Services\RpcSecurity;
Ashterix 13.1 130
Ashterix 23.1 131 use App\Services\UserService;
132 use Symfony\Component\Security\Core\Exception\UserNotFoundException;
133 use Ufo\JsonRpcBundle\Security\Interfaces\ITokenValidator;
134 use Ufo\RpcError\RpcInvalidTokenException;
135
136 class UserTokenValidator implements ITokenValidator
Ashterix 13.1 137 {
Ashterix 23.1 138
139 public function __construct(protected UserService $userService) {}
140
141 public function isValid(string $token): true
Ashterix 14.2 142 {
Ashterix 23.1 143 try {
144 $this->userService->getUserByToken($token);
145 return true;
146 } catch (UserNotFoundException $e) {
147 throw new RpcInvalidTokenException(previous: $e);
Ashterix 13.1 148 }
149 }
150 }
Ashterix 23.1 151 {{/code}}
Ashterix 14.2 152
153 (% class="box warningmessage" %)
154 (((
155 **ВАЖЛИВО!!!**
Ashterix 23.1 156 Метод {{code language="none"}}isValid{{/code}} має повертати {{code language="none"}}true{{/code}} якщо токен існує і валідний, або викидати {{code language="none"}}Ufo\RpcError\RpcInvalidTokenException{{/code}} в іншому разі.
Ashterix 14.2 157 )))
158
Ashterix 23.1 159 Після цього вам потрібно в файлі {{code language="none"}}config/services.yaml{{/code}} прописати що класи, що мають залежність від інтерфейса {{code language="none"}}ITokenValidator{{/code}} мають приймати ваш новий клас.
Ashterix 14.2 160
Ashterix 23.1 161 {{code language="yaml" layout="LINENUMBERS" title="config/services.yaml"}}
162 parameters:
163 # some parameters list
164 # ...
Ashterix 14.2 165
Ashterix 23.1 166 services:
167 # some services list
168 # ...
Ashterix 14.2 169
Ashterix 23.1 170 Ufo\JsonRpcBundle\Security\Interfaces\ITokenValidator:
171 class: App\Services\RpcSecurity\UserTokenValidator
172 {{/code}}
Ashterix 17.1 173
Ashterix 23.1 174 = Блок {{code language="none"}}async{{/code}} =
Ashterix 19.3 175
Ashterix 23.2 176 Цей блок для налаштування [[асинхронного транспорту>>doc:docs.JsonRpcBundle.functionality.async.WebHome]].
Ashterix 19.3 177
Ashterix 23.1 178 Додайте параметр {{code language="none"}}rpc_async{{/code}} який містить рядок у форматі DSN. Цей рядок є конфігурацією [[Symfony Messenger>>https://symfony.com/doc/current/messenger.html]], він вказує на асинхронний транспорт по якому RPC Server буде очікувати вхідні запити якщо у вас запущений консюмер ({{code language="none"}}php bin/console messenger:consume rpc_async{{/code}}). Для більш детального розуміння цього процесу читайте документацію [[Symfony Messenge>>https://symfony.com/doc/current/messenger.html]].
Ashterix 19.3 179
Ashterix 23.1 180 {{code language="yaml" layout="LINENUMBERS" title="config/packages/ufo_json_rpc.yaml"}}
181 ufo_json_rpc:
182 async:
183 rpc_async: '%env(resolve:RPC_TRANSPORT_DSN)%'
Ashterix 19.3 184
Ashterix 23.1 185 {{/code}}
Ashterix 19.3 186
Ashterix 21.2 187 (% class="box warningmessage" %)
188 (((
189 Це налаштування має на увазі, що у вас в змінних оточення встановлена змінна RPC_TRANSPORT_DSN що містить DSN рядок.
190 )))
191
Ashterix 23.1 192 = Блок {{code language="none"}}docs{{/code}} =
Ashterix 17.1 193
194 Це блок який налаштовує генерацію документації коли ви робите GET запит на RPC Server
195
Ashterix 23.1 196 == Секція {{code language="none"}}response{{/code}} ==
Ashterix 17.1 197
198 Містить налаштування, що відповідають за вміст відповіді.
199
Ashterix 23.1 200 === Параметр {{code language="none"}}key_for_methods{{/code}} ===
Ashterix 17.1 201
202 Цей параметр дозволяє вказати назву ключа у відповіді в якій буде віддаватися масив доступних сервісів.
203
Ashterix 23.1 204 Значення за замовченням {{code language="none"}}methods{{/code}}. Може мати будь-яке значення типу рядок.
Ashterix 17.1 205
Ashterix 23.1 206 {{code language="yaml" layout="LINENUMBERS" title="config/packages/ufo_json_rpc.yaml"}}
207 ufo_json_rpc:
208 docs:
209 key_for_methods: methods
210 {{/code}}
Ashterix 17.1 211
Ashterix 23.1 212 {{code language="yaml" layout="LINENUMBERS" title="config/packages/ufo_json_rpc.yaml"}}
213 ufo_json_rpc:
214 docs:
215 key_for_methods: services
216 {{/code}}
Ashterix 17.1 217
Ashterix 23.1 218 {{code language="yaml" layout="LINENUMBERS" title="config/packages/ufo_json_rpc.yaml"}}
219 ufo_json_rpc:
220 docs:
221 key_for_methods: some_custom_key
222 {{/code}}
Ashterix 17.1 223
Ashterix 23.1 224 === Параметр {{code language="none"}}async_dsn_info{{/code}} ===
Ashterix 19.4 225
226 Відповідає за відображення в документації інформації про асинхронний транспорт.
227
Ashterix 23.1 228 {{code language="yaml" layout="LINENUMBERS" title="config/packages/ufo_json_rpc.yaml"}}
229 ufo_json_rpc:
230 async_dsn_info: true # or false
231 {{/code}}
Ashterix 19.4 232
233 ==== **Приклад документації ** ====
234
Ashterix 23.1 235 {{code language="json" layout="LINENUMBERS" title="GET: /api"}}
Ashterix 19.4 236 {
Ashterix 23.1 237 "envelope": "JSON-RPC-2.0/UFO-RPC-6",
238 "contentType": "application/json",
239 "description": "",
240 "transport": {
241 "sync": {
242 "scheme": "http",
243 "host": "example.com",
244 "path": "/api",
245 "method": "POST"
Ashterix 19.4 246 },
Ashterix 23.1 247 "async": {
248 "scheme": "amqp",
249 "user": "{user}",
250 "pass": "{pass}",
251 "host": "async_rabbit",
252 "port": 5672,
253 "path": "/%2f/json-rpc"
Ashterix 19.4 254 }
255 },
Ashterix 23.1 256 "methods": {
257 ...
Ashterix 19.4 258 }
259 }
Ashterix 23.1 260 {{/code}}
Ashterix 19.4 261
Ashterix 23.1 262 {{info}}
Ashterix 19.4 263 Не переймайтеся щодо безпеки ваших авторизаційних даних. що містяться в DSN.
264
265 Документатор побудований таким чином, що перед виводом інформації про DSN він видаляє дані про користувача і його пароль, а також інші секретні дані, як то токени, секретні ключі, тощо.
266
Ashterix 23.1 267 Шаблон, по якому відбувається захист {{code language="none"}}/([\w\d_]*(?:secret|access|token|key)[_\w]*)=((?:\w|\d)+(?=&?))/{{/code}}.
Ashterix 19.4 268
269 Приклад:
270
Ashterix 23.1 271 {{code language="json" layout="LINENUMBERS" title="RPC_TRANSPORT_DSN=https://sqs.eu-west-3.amazonaws.com/123456789012/messages?access_key=AKIAIOSFODNN7EXAMPLE&secret_key=j17M97ffSVoKI0briFoo9a"}}
Ashterix 19.4 272 {
Ashterix 23.1 273 "async": {
274 "scheme": "https",
275 "host": "sqs.eu-west-3.amazonaws.com",
276 "path": "/123456789012/messages",
277 "query": "access_key={access_key}&secret_key={secret_key}"
Ashterix 19.4 278 }
279 }
Ashterix 23.1 280 {{/code}}
281 {{/info}}
Ashterix 19.4 282
Ashterix 23.1 283 === Параметр {{code language="none"}}validations{{/code}} ===
Ashterix 17.1 284
285 Відповідає за відображення в документації методів додаткових блоків, що вказують на вимоги до валідації даних.
286
287 Наразі цей блок має два можливих налаштування:
288
Ashterix 23.1 289 * {{code language="none"}}json_schema: <bool>{{/code}}
290 * {{code language="none"}}symfony_asserts: <bool>{{/code}}
Ashterix 17.1 291
Ashterix 23.1 292 У всіх опцій в цьому параметрі значення за замовченням {{code language="none"}}false{{/code}}, тобто ці блоки не будуть відображатися в документації.
293 Якщо ви потребуєте якийсь з цих блоків інформації при запиті документації, то встановіть значення в {{code language="none"}}true{{/code}}.
Ashterix 17.1 294
Ashterix 23.1 295 {{code language="yaml" layout="LINENUMBERS" title="config/packages/ufo_json_rpc.yaml"}}
296 ufo_json_rpc:
297 docs:
298 json_schema: true
299 symfony_asserts: true
300 {{/code}}
Ashterix 17.1 301
302 ==== **Приклад документації ** ====
303
304 (% class="box infomessage" %)
305 (((
306 В цьому прикладі я видалив вміст обʼєктів symfony_assertions для спрощення прикладу.
Ashterix 23.2 307 Детальніше про валідацію методів дивись сторінку **[[Валідація процедур>>doc:docs.JsonRpcBundle.add_rpc_service.assertions.WebHome]]**
Ashterix 17.1 308 )))
309
Ashterix 23.1 310 {{code language="json" layout="LINENUMBERS" title="GET: /api"}}
Ashterix 17.1 311 {
Ashterix 23.1 312 "envelope": "JSON-RPC-2.0/UFO-RPC-6",
313 "contentType": "application/json",
314 "description": "",
315 "transport": {
316 "sync": {
317 "scheme": "https",
318 "host": "example.com",
319 "path": "/api",
320 "method": "POST"
Ashterix 19.3 321 }
322 },
Ashterix 23.1 323 "methods": {
324 "getUserNameByUuid": {
325 "name": "getUserNameByUuid",
326 "description": "Get username by id",
327 "parameters": {
328 "userId": {
329 "type": "string",
330 "name": "userId",
331 "description": "User id in uuid format",
332 "optional": false
Ashterix 17.1 333 }
334 },
Ashterix 23.1 335 "returns": "string",
336 "responseFormat": "string",
337 "json_schema": {
338 "$schema": "http://json-schema.org/draft-07/schema#",
339 "type": "object",
340 "properties": {
341 "userId": {
342 "type": "string"
Ashterix 17.1 343 }
344 },
Ashterix 23.1 345 "required": [
346 "userId"
Ashterix 17.1 347 ]
348 },
Ashterix 23.1 349 "symfony_assertions": {
350 "userId": [
Ashterix 17.1 351 {
Ashterix 23.1 352 "class": "Symfony\\Component\\Validator\\Constraints\\Uuid",
353 "context": {}
Ashterix 17.1 354 }
355 ]
356 }
357 },
Ashterix 23.1 358 "sendEmail": {
359 "name": "sendEmail",
360 "description": "Send mail",
361 "parameters": {
362 "email": {
363 "type": "string",
364 "name": "email",
365 "description": "",
366 "optional": false
Ashterix 17.1 367 },
Ashterix 23.1 368 "subject": {
369 "type": "string",
370 "name": "subject",
371 "description": "",
372 "optional": false
Ashterix 17.1 373 },
Ashterix 23.1 374 "text": {
375 "type": "string",
376 "name": "text",
377 "description": "",
378 "optional": false
Ashterix 17.1 379 }
380 },
Ashterix 23.1 381 "returns": "boolean",
382 "responseFormat": "boolean",
383 "json_schema": {
384 "$schema": "http://json-schema.org/draft-07/schema#",
385 "type": "object",
386 "properties": {
387 "email": {
388 "type": "string",
389 "format": "email"
Ashterix 17.1 390 },
Ashterix 23.1 391 "subject": {
392 "type": "string",
393 "minLength": 1,
394 "maxLength": 100
Ashterix 17.1 395 },
Ashterix 23.1 396 "text": {
397 "type": "string",
398 "minLength": 10
Ashterix 17.1 399 }
400 },
Ashterix 23.1 401 "required": [
402 "email",
403 "subject",
404 "text"
Ashterix 17.1 405 ]
406 },
Ashterix 23.1 407 "symfony_assertions": {
408 "email": [
Ashterix 17.1 409 {
Ashterix 23.1 410 "class": "Symfony\\Component\\Validator\\Constraints\\Email",
411 "context": {}
Ashterix 17.1 412 }
413 ],
Ashterix 23.1 414 "subject": [
Ashterix 17.1 415 {
Ashterix 23.1 416 "class": "Symfony\\Component\\Validator\\Constraints\\NotBlank",
417 "context": {}
Ashterix 17.1 418 },
419 {
Ashterix 23.1 420 "class": "Symfony\\Component\\Validator\\Constraints\\Length",
421 "context": {}
Ashterix 17.1 422 }
423 ],
Ashterix 23.1 424 "text": [
Ashterix 17.1 425 {
Ashterix 23.1 426 "class": "Symfony\\Component\\Validator\\Constraints\\NotBlank",
427 "context": {}
Ashterix 17.1 428 },
429 {
Ashterix 23.1 430 "class": "Symfony\\Component\\Validator\\Constraints\\Length",
431 "context": {}
Ashterix 17.1 432 }
433 ]
434 }
435 }
436 }
437 }
Ashterix 23.1 438 {{/code}}