Версія 6: Налаштування
Всі налаштування бандла знаходяться в файлі config/packages/ufo_json_rpc.yaml.
Є можливість налаштувати параметри захисту API та деякі параметри формату даних, що віддається при запиті документації.
Блок security
Наразі єдиним механізмом захисту доступу до вашого API є встановлення перевірки ключа доступу (api_token).
Параметр protected_methods
Цей параметр приймає масив назв http методів, які мають бути захищені.
За замовченням ввімкнут захист лише для методу POST. Ви можете:
- вказати пустий масив [] щоб зробити API повністю відкритим
2
3
security:
protected_methods: []
- вказати додатково захист для методу GET, що зробить запит документації недоступним без токену в заголовках запиту
2
3
security:
protected_methods: ['GET', 'POST']
protected_methods, вам необхідно налаштувати токени, по яким буде відкритий доступ.
Якщо ви захищаєте ваш API черезПерш за все, треба визначитися з назвою токену.
Параметр token_key_in_header
Компонент RpcSecurity буде шукати в заголовках запиту специфічний ключ, який ви можете встановити в налаштуваннях пакету, значення за замовченням token_key_in_header: 'Ufo-RPC-Token', ви можете встановити будь-яке інше значення яке відповідає наступним вимогам.
Вимоги до формування заголовків протоколу HTTP
Параметр clients_tokens
Тепер слід вказати масив клієнтськіх токенів, які будуть мати доступ до API.
Тут є певна варіативність.
Токени в параметрах
Є можливість прописати токени хардкодом прямо в файлі налаштувань.
Це погано з позиції безпеки, якщо код зберігається в публічному репозиторію, то до цього токену буде мати доступ кожен.
2
3
4
5
6
7
security:
protected_methods: ['GET', 'POST']
token_key_in_header: 'Ufo-RPC-Token'
clients_tokens:
- 'ClientTokenExample' # hardcoded token example. Importantly!!! Replace or delete it!
Токени в змінних оточення
Це найбільш доцільний механізм у разі, якщо ви розробляєте сервіс для розподіленого бекенду, що написаний на SOA (Сервіс-Орієнтована Архітектура). Зазвичай, в такому випадку, вам треба відкрити доступ до апі одному або обмеженій кількості клієнтських додатків і оновлення ключів не буде відбуватися занадто часто.
В такому випадку можна прописати токени в змінних оточення (файл .env.local під час локальної розробки). Цей механізм достатньо безпечний з боку збереження доступів.
2
TOKEN_FOR_APP_2=456fg87g8h98jmnb8675r4445n8up365
2
3
4
5
6
7
security:
protected_methods: ['GET', 'POST']
token_key_in_header: 'Ufo-RPC-Token'
clients_tokens:
- '%env(resolve:TOKEN_FOR_APP_1)%' # token example from .env.local
- '%env(resolve:TOKEN_FOR_APP_2)%' # token example from .env.local
Токени для користувача
Припускаю, що у вас може виникнути потреба зробити персональні ключі для користувачів вашого додатку, можливо ви захочете впровадити ліміти або інші обмеження.
В такому випадку вам не потрібно вказувати перелік токенів в конфігах, ви можете зберігати їх в базі даних або іншому місці згідно вашій бізнес-логіки. Єдина вимога, у вас має бути сервіс, який вміє перевіряти чи існує наданий токен.
Для того, щоб JsonRpcServer міг використовувати вашу логіку, доведеться реалізувати власний клас, що реалізує інтерфейс Ufo\JsonRpcBundle\Security\Interfaces\ITokenValidator
Приклад власного валідатора токенів
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
namespace App\Services\RpcSecurity;
use App\Services\UserService;
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
use Ufo\JsonRpcBundle\Security\Interfaces\ITokenValidator;
use Ufo\RpcError\RpcInvalidTokenException;
class UserTokenValidator implements ITokenValidator
{
public function __construct(protected UserService $userService) {}
public function isValid(string $token): true
{
try {
$this->userService->getUserByToken($token);
return true;
} catch (UserNotFoundException $e) {
throw new RpcInvalidTokenException(previous: $e);
}
}
}
Після цього вам потрібно в файлі config/services.yaml прописати що класи, що мають залежність від інтерфейса ITokenValidator мають приймати ваш новий клас.
2
3
4
5
6
7
8
9
10
# some parameters list
# ...
services:
# some services list
# ...
Ufo\JsonRpcBundle\Security\Interfaces\ITokenValidator:
class: App\Services\RpcSecurity\UserTokenValidator
Блок async
Цей блок для налаштування асинхронного транспорту.
Додайте параметр rpc_async який містить рядок у форматі DSN. Цей рядок є конфігурацією Symfony Messenger, він вказує на асинхронний транспорт по якому RPC Server буде очікувати вхідні запити якщо у вас запущений консюмер (php bin/console messenger:consume rpc_async). Для більш детального розуміння цього процесу читайте документацію Symfony Messenge.
2
3
4
async:
rpc_async: '%env(resolve:RPC_TRANSPORT_DSN)%'
Блок docs
Це блок який налаштовує генерацію документації коли ви робите GET запит на RPC Server
Секція response
Містить налаштування, що відповідають за вміст відповіді.
Параметр key_for_methods
Цей параметр дозволяє вказати назву ключа у відповіді в якій буде віддаватися масив доступних сервісів.
Значення за замовченням methods. Може мати будь-яке значення типу рядок.
2
3
docs:
key_for_methods: methods
2
3
docs:
key_for_methods: services
2
3
docs:
key_for_methods: some_custom_key
Параметр async_dsn_info
Відповідає за відображення в документації інформації про асинхронний транспорт.
2
async_dsn_info: true # or false
Приклад документації
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
"envelope": "JSON-RPC-2.0/UFO-RPC-6",
"contentType": "application/json",
"description": "",
"transport": {
"sync": {
"scheme": "http",
"host": "example.com",
"path": "/api",
"method": "POST"
},
"async": {
"scheme": "amqp",
"user": "{user}",
"pass": "{pass}",
"host": "async_rabbit",
"port": 5672,
"path": "/%2f/json-rpc"
}
},
"methods": {
...
}
}
Параметр validations
Відповідає за відображення в документації методів додаткових блоків, що вказують на вимоги до валідації даних.
Наразі цей блок має два можливих налаштування:
- json_schema: <bool>
- symfony_asserts: <bool>
У всіх опцій в цьому параметрі значення за замовченням false, тобто ці блоки не будуть відображатися в документації.
Якщо ви потребуєте якийсь з цих блоків інформації при запиті документації, то встановіть значення в true.
2
3
4
docs:
json_schema: true
symfony_asserts: true
Приклад документації
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
"envelope": "JSON-RPC-2.0/UFO-RPC-6",
"contentType": "application/json",
"description": "",
"transport": {
"sync": {
"scheme": "https",
"host": "example.com",
"path": "/api",
"method": "POST"
}
},
"methods": {
"getUserNameByUuid": {
"name": "getUserNameByUuid",
"description": "Get username by id",
"parameters": {
"userId": {
"type": "string",
"name": "userId",
"description": "User id in uuid format",
"optional": false
}
},
"returns": "string",
"responseFormat": "string",
"json_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"userId": {
"type": "string"
}
},
"required": [
"userId"
]
},
"symfony_assertions": {
"userId": [
{
"class": "Symfony\\Component\\Validator\\Constraints\\Uuid",
"context": {}
}
]
}
},
"sendEmail": {
"name": "sendEmail",
"description": "Send mail",
"parameters": {
"email": {
"type": "string",
"name": "email",
"description": "",
"optional": false
},
"subject": {
"type": "string",
"name": "subject",
"description": "",
"optional": false
},
"text": {
"type": "string",
"name": "text",
"description": "",
"optional": false
}
},
"returns": "boolean",
"responseFormat": "boolean",
"json_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email"
},
"subject": {
"type": "string",
"minLength": 1,
"maxLength": 100
},
"text": {
"type": "string",
"minLength": 10
}
},
"required": [
"email",
"subject",
"text"
]
},
"symfony_assertions": {
"email": [
{
"class": "Symfony\\Component\\Validator\\Constraints\\Email",
"context": {}
}
],
"subject": [
{
"class": "Symfony\\Component\\Validator\\Constraints\\NotBlank",
"context": {}
},
{
"class": "Symfony\\Component\\Validator\\Constraints\\Length",
"context": {}
}
],
"text": [
{
"class": "Symfony\\Component\\Validator\\Constraints\\NotBlank",
"context": {}
},
{
"class": "Symfony\\Component\\Validator\\Constraints\\Length",
"context": {}
}
]
}
}
}
}