Зміни в документі 2. Налаштування бандла

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

Від версії 2.1
редаговано Ashterix
дата 2024/07/11 09:58
Змінити коментар: Немає коментарів для цієї версії
До версії 3.1
редаговано Ashterix
дата 2024/07/11 11:40
Змінити коментар: Немає коментарів для цієї версії

Підсумок

Подробиці

Властивості сторінки
Назва
... ... @@ -1,1 +1,1 @@
1 -tmp
1 +2. Налаштування бандла
Вміст
... ... @@ -1,0 +1,377 @@
1 +{{box cssClass="floatinginfobox" title="**Зміст**"}}
2 +{{toc/}}
3 +{{/box}}
4 +
5 +{{info}}
6 +Конфігурація зазнала суттєвих змін і не має зворотної сумісності з версією 6.
7 +{{/info}}
8 +
9 +(% class="wikigeneratedid" %)
10 +Всі налаштування бандла знаходяться в файлі {{code language="none"}}config/packages/ufo_json_rpc.yaml{{/code}}.
11 +
12 +(% class="wikigeneratedid" %)
13 +Є можливість налаштувати параметри захисту API та деякі параметри формату даних, що віддається при запиті документації.
14 +
15 += Блок {{code language="none"}}security{{/code}} =
16 +
17 +Наразі єдиним механізмом захисту доступу до вашого API є встановлення перевірки ключа доступу (api_token).
18 +
19 +== Параметри {{code language="none"}}protected_api{{/code}} та {{code language="none"}}protected_doc{{/code}} (boolean) ==
20 +
21 +(% class="wikigeneratedid" %)
22 +Ці параметри вказує чи мають бути захищені API методи та документація, відповідно.
23 +
24 +(% class="wikigeneratedid" %)
25 +За замовченням апі методи захищені, а документація відкрита.
26 +
27 +{{code language="yaml" layout="LINENUMBERS" title="config/packages/ufo_json_rpc.yaml"}}
28 +ufo_json_rpc:
29 + security:
30 + protected_api: true # Protection API requests
31 + protected_doc: false # Protection API documentation
32 +{{/code}}
33 +
34 +(% id="cke_bm_164641S" style="display:none" %) (%%)Якщо ви захищаєте ваш API через {{code language="none"}}protected_api{{/code}}, вам необхідно налаштувати токени, по яким буде відкритий доступ.
35 +
36 +Перш за все, треба визначитися з назвою токену.
37 +
38 +== Параметр {{code language="none"}}token_name{{/code}} ==
39 +
40 +Компонент {{code language="none"}}RpcSecurity{{/code}} буде шукати в заголовках запиту специфічний ключ, який ви можете встановити в налаштуваннях пакету, значення за замовченням {{code language="none"}}token_name: 'Ufo-RPC-Token'{{/code}}, ви можете встановити будь-яке інше значення яке відповідає наступним вимогам.
41 +
42 +{{spoiler title=" Вимоги до формування заголовків протоколу HTTP"}}
43 +Вимоги до назв заголовків HTTP не є строго регульованими щодо капіталізації, оскільки HTTP заголовки нечутливі до регістру. Однак, існують деякі загальні практики і стандарти, які зазвичай дотримуються для кращої читабельності та узгодженості:
44 +
45 +- Капіталізація: Зазвичай назви HTTP заголовків пишуться з використанням CamelCase, де кожне слово починається з великої літери, наприклад, Content-Type, User-Agent, Accept-Encoding. Це не впливає на технічну обробку заголовків, але робить їх легше читати.
46 +- Унікальність: Кожен заголовок повинен мати унікальну назву у контексті одного HTTP запиту або відповіді. Не можна використовувати однакові назви для різних заголовків у тому самому запиті чи відповіді.
47 +- Спеціальні заголовки: Існують заголовки, які використовуються специфічно для контролю поведінки кешування (Cache-Control), безпеки (Strict-Transport-Security), аутентифікації (Authorization), тощо.
48 +- Норми RFC: Вимоги до заголовків регулюються документами RFC, які визначають стандарти для протоколів Інтернету. Наприклад, загальні заголовки і їхнє використання описані в RFC 7231.
49 +{{/spoiler}}
50 +
51 +
52 +
53 +
54 +
55 +
56 +
57 +
58 +
59 +
60 +
61 +
62 +
63 +
64 +
65 +
66 +
67 +
68 +Параметр {{code language="none"}}clients_tokens{{/code}}
69 +
70 +Тепер слід вказати масив клієнтськіх токенів, які будуть мати доступ до API.
71 +
72 +Тут є певна варіативність.
73 +
74 +=== Токени в параметрах ===
75 +
76 +(% class="box errormessage" %)
77 +(((
78 +**НЕ РЕКОМЕНДОВАНО!!!**
79 +\\Цей підхід допускається лише для локального тестування API
80 +)))
81 +
82 +Є можливість прописати токени хардкодом прямо в файлі налаштувань.
83 +
84 +Це погано з позиції безпеки, якщо код зберігається в публічному репозиторію, то до цього токену буде мати доступ кожен.
85 +
86 +{{code language="yaml" layout="LINENUMBERS" title="config/packages/ufo_json_rpc.yaml"}}
87 +ufo_json_rpc:
88 + security:
89 + token_name: 'Ufo-RPC-Token'
90 + clients_tokens:
91 + - 'ClientTokenExample' # hardcoded token example. Importantly!!! Replace or delete it!
92 +
93 +{{/code}}
94 +
95 +=== Токени в змінних оточення ===
96 +
97 +Це найбільш доцільний механізм у разі, якщо ви розробляєте сервіс для розподіленого бекенду, що написаний на SOA (Сервіс-Орієнтована Архітектура). Зазвичай, в такому випадку, вам треба відкрити доступ до апі одному або обмеженій кількості клієнтських додатків і оновлення ключів не буде відбуватися занадто часто.
98 +
99 +В такому випадку можна прописати токени в змінних оточення (файл {{code language="none"}}.env.local{{/code}} під час локальної розробки). Цей механізм достатньо безпечний з боку збереження доступів.
100 +
101 +(((
102 +{{code language="ini" layout="LINENUMBERS" title=".env.local"}}
103 +TOKEN_FOR_APP_1=9363074966579432364f8b73b3318f71
104 +TOKEN_FOR_APP_2=456fg87g8h98jmnb8675r4445n8up365
105 +{{/code}}
106 +
107 +{{code language="yaml" layout="LINENUMBERS" title="config/packages/ufo_json_rpc.yaml"}}
108 +ufo_json_rpc:
109 + security:
110 + token_key_in_header: 'Ufo-RPC-Token'
111 + clients_tokens:
112 + - '%env(resolve:TOKEN_FOR_APP_1)%' # token example from .env.local
113 + - '%env(resolve:TOKEN_FOR_APP_2)%' # token example from .env.local
114 +{{/code}}
115 +)))
116 +
117 +=== Токени для користувача ===
118 +
119 +Припускаю, що у вас може виникнути потреба зробити персональні ключі для користувачів вашого додатку, можливо ви захочете впровадити ліміти або інші обмеження.
120 +В такому випадку вам не потрібно вказувати перелік токенів в конфігах, ви можете зберігати їх в базі даних або іншому місці згідно вашій бізнес-логіки. Єдина вимога, у вас має бути сервіс, який вміє перевіряти чи існує наданий токен.
121 +
122 +Для того, щоб JsonRpcServer міг використовувати вашу логіку, доведеться реалізувати власний клас, що реалізує інтерфейс {{code language="none"}}Ufo\JsonRpcBundle\Security\Interfaces\ITokenValidator{{/code}}
123 +
124 +{{code language="php" layout="LINENUMBERS" title="==== Приклад власного валідатора токенів ===="}}
125 +<?php
126 +
127 +namespace App\Services\RpcSecurity;
128 +
129 +use App\Services\UserService;
130 +use Symfony\Component\Security\Core\Exception\UserNotFoundException;
131 +use Ufo\JsonRpcBundle\Security\Interfaces\ITokenValidator;
132 +use Ufo\RpcError\RpcInvalidTokenException;
133 +
134 +class UserTokenValidator implements ITokenValidator
135 +{
136 +
137 + public function __construct(protected UserService $userService) {}
138 +
139 + public function isValid(string $token): true
140 + {
141 + try {
142 + $this->userService->getUserByToken($token);
143 + return true;
144 + } catch (UserNotFoundException $e) {
145 + throw new RpcInvalidTokenException(previous: $e);
146 + }
147 + }
148 +}
149 +{{/code}}
150 +
151 +(% class="box warningmessage" %)
152 +(((
153 +**ВАЖЛИВО!!!**
154 +Метод {{code language="none"}}isValid{{/code}} має повертати {{code language="none"}}true{{/code}} якщо токен існує і валідний, або викидати {{code language="none"}}Ufo\RpcError\RpcInvalidTokenException{{/code}} в іншому разі.
155 +)))
156 +
157 +Після цього вам потрібно в файлі {{code language="none"}}config/services.yaml{{/code}} прописати що класи, що мають залежність від інтерфейса {{code language="none"}}ITokenValidator{{/code}} мають приймати ваш новий клас.
158 +
159 +{{code language="yaml" layout="LINENUMBERS" title="config/services.yaml"}}
160 +parameters:
161 + # some parameters list
162 + # ...
163 +
164 +services:
165 + # some services list
166 + # ...
167 +
168 + Ufo\JsonRpcBundle\Security\Interfaces\ITokenValidator:
169 + class: App\Services\RpcSecurity\UserTokenValidator
170 +{{/code}}
171 +
172 += Блок {{code language="none"}}async{{/code}} =
173 +
174 +Цей блок для налаштування [[асинхронного транспорту>>doc:docs.JsonRpcBundle.functionality.async.WebHome]].
175 +
176 +Додайте параметр {{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]].
177 +
178 +{{code language="yaml" layout="LINENUMBERS" title="config/packages/ufo_json_rpc.yaml"}}
179 +ufo_json_rpc:
180 + async:
181 + rpc_async: '%env(resolve:RPC_TRANSPORT_DSN)%'
182 +
183 +{{/code}}
184 +
185 +(% class="box warningmessage" %)
186 +(((
187 +Це налаштування має на увазі, що у вас в змінних оточення встановлена змінна RPC_TRANSPORT_DSN що містить DSN рядок.
188 +)))
189 +
190 += Блок {{code language="none"}}docs{{/code}} =
191 +
192 +Цей блок налаштовує деякі параметри генерації документації коли ви робите GET запит на RPC Server.
193 +
194 +(% class="box infomessage" %)
195 +(((
196 +Починаючи з версії 7, JsonRpcBundle генерує API документацію, що відповідає специфікації [[OpenRpc>>https://spec.open-rpc.org/]]
197 +)))
198 +
199 +* {{code language="none"}}project_name{{/code}}: Назва проєкту, що буде відображена в документації
200 +* {{code language="none"}}project_description{{/code}}: Опис проєкту
201 +* {{code language="none"}}project_version{{/code}}: Поточна версія вашого API
202 +* {{code language="none"}}async_dsn_info{{/code}}: Відповідає за відображення в документації інформації про асинхронний транспорт
203 +* (% id="cke_bm_826282S" style="display:none" %) {{code language="none"}}validations.symfony_asserts{{/code}}(%%): <bool> Відповідає за відображення рядку очікувань валідації для параметра (якщо ви використовуєте [[валідацію>>doc:docs.JsonRpcBundle.add_rpc_service.assertions.WebHome]])
204 +
205 +{{code language="yaml" layout="LINENUMBERS" title="config/packages/ufo_json_rpc.yaml"}}
206 +ufo_json_rpc:
207 + docs:
208 + project_name: 'My Project'
209 + project_description: 'My project description'
210 + project_version: '1.0'
211 + # Optional response details
212 + async_dsn_info: false # Provide information about API that work asynchronously
213 + validations:
214 + symfony_asserts: false # Indicates if an array of Symfony validation constraints is used
215 +
216 +{{/code}}
217 +
218 +==== **Приклад документації ** ====
219 +
220 +{{code language="json" layout="LINENUMBERS" title="GET: /api"}}
221 +{
222 + "envelope": "JSON-RPC-2.0/UFO-RPC-6",
223 + "contentType": "application/json",
224 + "description": "",
225 + "transport": {
226 + "sync": {
227 + "scheme": "http",
228 + "host": "example.com",
229 + "path": "/api",
230 + "method": "POST"
231 + },
232 + "async": {
233 + "scheme": "amqp",
234 + "user": "{user}",
235 + "pass": "{pass}",
236 + "host": "async_rabbit",
237 + "port": 5672,
238 + "path": "/%2f/json-rpc"
239 + }
240 + },
241 + "methods": {
242 + ...
243 + }
244 +}
245 +{{/code}}
246 +
247 +{{info}}
248 +Не переймайтеся щодо безпеки ваших авторизаційних даних. що містяться в DSN.
249 +
250 +Документатор побудований таким чином, що перед виводом інформації про DSN він видаляє дані про користувача і його пароль, а також інші секретні дані, як то токени, секретні ключі, тощо.
251 +
252 +Шаблон, по якому відбувається захист {{code language="none"}}/([\w\d_]*(?:secret|access|token|key)[_\w]*)=((?:\w|\d)+(?=&?))/{{/code}}.
253 +
254 +Приклад:
255 +
256 +{{code language="json" layout="LINENUMBERS" title="RPC_TRANSPORT_DSN=https://sqs.eu-west-3.amazonaws.com/123456789012/messages?access_key=AKIAIOSFODNN7EXAMPLE&secret_key=j17M97ffSVoKI0briFoo9a"}}
257 +{
258 + "async": {
259 + "scheme": "https",
260 + "host": "sqs.eu-west-3.amazonaws.com",
261 + "path": "/123456789012/messages",
262 + "query": "access_key={access_key}&secret_key={secret_key}"
263 + }
264 +}
265 +{{/code}}
266 +{{/info}}
267 +
268 +=== Параметр {{code language="none"}}validations{{/code}} ===
269 +
270 +Відповідає за відображення в документації методів додаткових блоків, що вказують на вимоги до валідації даних.
271 +
272 +Наразі цей блок має два можливих налаштування:
273 +
274 +* {{code language="none"}}json_schema: <bool>{{/code}}
275 +* {{code language="none"}}symfony_asserts: <bool>{{/code}}
276 +
277 +У всіх опцій в цьому параметрі значення за замовченням {{code language="none"}}false{{/code}}, тобто ці блоки не будуть відображатися в документації.
278 +Якщо ви потребуєте якийсь з цих блоків інформації при запиті документації, то встановіть значення в {{code language="none"}}true{{/code}}.
279 +
280 +{{code language="yaml" layout="LINENUMBERS" title="config/packages/ufo_json_rpc.yaml"}}
281 +ufo_json_rpc:
282 + docs:
283 + project_name: 'My Project'
284 + project_description: ''
285 + project_version: null
286 + # Optional response details
287 + async_dsn_info: false # Provide information about API that work asynchronously
288 + validations:
289 + symfony_asserts: false # Indicates if an array of Symfony validation constraints is used
290 +
291 +{{/code}}
292 +
293 +==== **Приклад документації ** ====
294 +
295 +(% class="box infomessage" %)
296 +(((
297 +В цьому прикладі я видалив вміст обʼєктів symfony_assertions для спрощення прикладу.
298 +Детальніше про валідацію методів дивись сторінку **[[Валідація процедур>>doc:docs.JsonRpcBundle.add_rpc_service.assertions.WebHome]]**
299 +)))
300 +
301 +{{code language="json" layout="LINENUMBERS" title="GET: /api"}}
302 +{
303 + "openrpc":"1.2.6",
304 + "info":{
305 + "title":"My Project",
306 + "description":"My project description",
307 + "contact":{
308 + "name":"ufo-tech/json-rpc-bundle",
309 + "url":"https://docs.ufo-tech.space/bin/view/docs/JsonRpcBundle/?language=en"
310 + },
311 + "license":{
312 + "name":"MIT"
313 + },
314 + "version":"1.0"
315 + },
316 + "servers":[
317 + {
318 + "url":"https://mysite.com/api",
319 + "description":"Json-RPC api server from UFO Tec\n\nUFO Tech, or Universal Flexible Open Technologies, is an initiative aimed at providing PHP developers with tools to create complex yet user-friendly solutions for modern web applications and service-oriented architectures.",
320 + "name":"UFO Json-RPC Server v.7.0.0",
321 + "x-method":"POST",
322 + "x-ufo":{
323 + "envelop":"JSON-RPC-2.0/UFO-RPC-7.0.0",
324 + "transport":{
325 + "sync":{
326 + "scheme":"https",
327 + "host":"mysite.com",
328 + "path":"/api",
329 + "method":"POST"
330 + },
331 + "async":{
332 + "scheme":"amqp",
333 + "user":"{user}",
334 + "pass":"{pass}",
335 + "host":"mysite.com",
336 + "port":5672,
337 + "path":"/%2f/json-rpc"
338 + }
339 + },
340 + "documentation":{
341 + "json-rpc":"https://www.jsonrpc.org/specification",
342 + "ufo-tech/json-rpc-bundle":"https://docs.ufo-tech.space/bin/view/docs/JsonRpcBundle/?language=en"
343 + }
344 + }
345 + }
346 + ],
347 + "methods":[
348 + {
349 + "name":"getUserNameByUuid",
350 + "tags":[
351 + {
352 + "name":"App\\Api\\UserApiService"
353 + }
354 + ],
355 + "summary":"Get username by id",
356 + "params":[
357 + {
358 + "name":"userId",
359 + "description":"User Id format uuid",
360 + "required":true,
361 + "schema":{
362 + "type":"string"
363 + },
364 + "x-ufo-assertions": "new Assert\\Uuid()"
365 + }
366 + ],
367 + "result":{
368 + "name":"string",
369 + "description":"User Name",
370 + "schema":{
371 + "type":"string"
372 + }
373 + }
374 + }
375 + ]
376 +}
377 +{{/code}}