Допустим, возникла задача ограничить доступ пользователей к серверу, основываясь на домене, например, разрешить просмотр видео только с определенного домена. Эта задача может быть решена при помощи REST hooks.
WCS передает в REST-запросе типа 1 "connect" к бэкенд-серверу поле "origin", содержащее доменное имя WCS-сервера, по которому к нему обратился пользователь, например
{ "nodeId" : "5tWOFn5ZoMQs22KrEls2Ulhee57hQO9D", "appKey" : "defaultApp", "sessionId" : "/5.44.168.45:53438/abcdef0123456789", "useWsTunnel" : false, "useWsTunnelPacketization2" : false, "useBase64BinaryEncoding" : false, "mediaProviders" : [ "WebRTC", "MSE", "WSPlayer" ], "clientVersion" : "0.5.28", "clientOSVersion" : "5.0 (Windows)", "clientBrowserVersion" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0", "keepAlive" : false, "origin" : "https://test2.flashphoner.com:8888" } |
Таким образом, для авторизации пользователя по домену необходимо реализовать REST hook типа 1 "connect".
1. REST hook типа 1 должен быть доступен на веб-сервере как
http://yourhost/rest-hooks/connect |
2. REST hook должен обрабатывать POST application/json HTTP запросы.
3. REST hook должен возвращать в теле ответа в точности то же, что он получил в запросе, за исключением настройки restClientConfig.
4. WCS сервер должен быть настроен на работу с REST hook следующим образом:
ssh -p 2001 admin@localhost >update app defaultApp -l http://yourhost/rest-hooks |
Обращения к REST методу можно отслеживать в логе сервера
tail -f /usr/local/FlashphonerWebCallServer/logs/server_logs/flashphoner.log |
В первых строках скрипта определяется метод и декодируется тело запроса. Здесь же задаем домен для авторизации:
<?php $api_method = array_pop(explode("/", $_SERVER['REQUEST_URI'])); $incoming_data = json_decode(file_get_contents('php://input'), true); $domain = "yourdomain.com"; |
Начинается обработка метода "connect". Здесь определяется переданное в запросе поле "origin" и заполняется поле "restClientConfig" для ответа:
switch($api_method) { case"connect": $origin = $incoming_data['origin']; //logs error_log("sessionId: " . $incoming_data['sessionId']); error_log("origin: " . $origin); $rest_client_config = json_decode(file_get_contents('rest_client_config.json'), true); $incoming_data['restClientConfig'] = $rest_client_config; |
Проверка домена. Если домен не найден, вызывается функция ubnormalResponse для формирования отрицательного ответа
$found = strpos($origin, $domain); if ($found !== false){ error_log("User authorized by domain " . $domain); }else{ error_log("User not authorized by domain: " . $domain . " Connection failed with 403 status."); ubnormalResponse(403); } break; } |
Вывод ответа на запрос
header('Content-Type: application/json'); echo json_encode($incoming_data); |
Функция ubnormalResponse завершает скрипт:
function ubnormalResponse($code) { if ($code == 403) { header('HTTP/1.1 403 Forbidden', true, $code); } else { header(':', true, $code); } die(); } ?> |
<?php $api_method = array_pop(explode("/", $_SERVER['REQUEST_URI'])); $incoming_data = json_decode(file_get_contents('php://input'), true); $domain = "yourdomain.com"; switch($api_method) { case"connect": $origin = $incoming_data['origin']; //logs error_log("sessionId: " . $incoming_data['sessionId']); error_log("origin: " . $origin); $rest_client_config = json_decode(file_get_contents('rest_client_config.json'), true); $incoming_data['restClientConfig'] = $rest_client_config; $found = strpos($origin, $domain); if ($found !== false){ error_log("User authorized by domain " . $domain); }else{ error_log("User not authorized by domain: " . $domain . " Connection failed with 403 status."); ubnormalResponse(403); } break; } header('Content-Type: application/json'); echo json_encode($incoming_data); function ubnormalResponse($code) { if ($code == 403) { header('HTTP/1.1 403 Forbidden', true, $code); } else { header(':', true, $code); } die(); } ?> |
{ "ConnectionStatusEvent" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "RegistrationStatusEvent" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "sendXcapRequest" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "XcapStatusEvent" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "sendDtmf" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "call" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "OnCallEvent" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "answer" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "hangup" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "hold" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "unhold" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "transfer" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "OnTransferEvent" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "FAIL", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "TransferStatusEvent" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "CallStatusEvent" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "sendMessage" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "FAIL", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "OnMessageEvent" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "MessageStatusEvent" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "publishStream" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "unPublishStream" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "playStream" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "stopStream" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "StreamStatusEvent" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "subscribe" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "SubscriptionStatusEvent" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "OnDataEvent" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "DataStatusEvent" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "submitBugReport" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "BugReportStatusEvent" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "pushLogs" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "RecordingStatusEvent" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "ErrorStatusEvent" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" }, "disconnect" : { "clientExclude" : "", "restExclude" : "", "restOnError" : "LOG", "restPolicy" : "NOTIFY", "restOverwrite" : "" } } |