Защита доступа к потокам без бекенда¶
В этой статье приведен пример того, как можно реализовать систему авторизации без написания собственного бэкенда.
Схема работы авторизации: 1. Ваш сайт генерирует токен по несложной формуле и хеширует его с помощью секретного ключа. 2. Клиент открывает поток с полученным токеном. 3. Flussonic генерирует токен по той же формуле, используя тот же ключ (и дополнительно используя имя потока и (необязательно) IP-адрес клиента). 4. Хеши совпали — доступ разрешен, не совпали — запрещен.
Настройка Flussonic для использования авторизации по токену¶
В поставке Flussonic есть вся необходимая логика для проверки генерируемых токенов. Достаточно просто указать опцию securetoken
и пароль для авторизации:
stream example-stream {
input fake://fake;
on_play securetoken://SECRETKEY;
}
Если вы хотите исключить из проверки IP-адрес клиента, добавьте опцию no_check_ip=true
в конфигурацию:
stream example-stream {
input fake://fake;
on_play securetoken://SECRETKEY?no_check_ip=true;
}
Можно включить авторизацию (директиву auth) как для одного потока, так и глобально.
Код для сайта¶
Чтобы сгенерировать токен, Flussonic должен знать следующее:
- (необязательно) IP-адрес клиента,
- имя потока,
- секретный ключ,
- текущее время,
- (необязательно)
user_id
, уникальный идентификатор пользователя, который используется для ограничения количества сессий (см. Ограничение количества сессий на пользователя).
Код на сайте должен собрать эти данные в одну строку:
string
= streamname + ip + starttime + endtime + secretkey + salt + user_id
И получить токен по формуле:
sha1(string) + salt + endtime + starttime
,
где:
ip
— IP адрес клиентского устройства.streamname
— название потока.starttime
— это текущее время UTC (в Unix Timestamp).endtime
— время окончания жизни токена (обычно это текущее время + несколько часов). По прошествии этого времени токен перестанет работать и его надо будет запрашивать заново.secretkey
— это ключ, указанный в файле/etc/flussonic/flussonic.conf
.salt
— строка из случайных символов. Необходима, чтобы для одинаковых входных данных генерировались разные токены.user_id
— строка, получаемая от системы биллинга/middleware (необязательно).
Если клиентские устройства находятся за прокси или их IP могут часто меняться, вы можете исключить IP-адрес клиента при формировании токена.
PHP пример¶
<?php
$flussonic = $_GET['host']; // This script gets Flussonic address from a query. String 'http://flussonic-ip'
$key = 'SECRETKEY'; // The key from flussonic.conf file. KEEP IT IN SECRET.
$lifetime = 3600 * 3; // The link will become invalid in 3 hours.
$stream = $_GET['stream']; // This script gets the stream name from a query. string (script.php?stream=bbc)
$ipaddr = $_SERVER['REMOTE_ADDR']; // (v20.07) Set $ipaddr = 'no_check_ip' if you want to exclude IP address of client devices from checking.
$desync = 300; // Allowed time desync between Flussonic and hosting servers in seconds.
$starttime = time() - $desync;
$endtime = $starttime + $lifetime;
$salt = bin2hex(openssl_random_pseudo_bytes(16));
$hashsrt = $stream.$ipaddr.$starttime.$endtime.$key.$salt;
$hash = sha1($hashsrt);
$token = $hash.'-'.$salt.'-'.$endtime.'-'.$starttime;
$link = $flussonic.'/'.$stream.'/embed.html?token='.$token.'&remote='.$ipaddr;
$embed = '<iframe allowfullscreen style="width:640px; height:480px;" src="'.$link.'"></iframe>';
echo $embed;
?>
Rails пример¶
config/routes.rb
:
Rails.application.routes.draw do
...
get '/securetoken/:id', to: 'securetoken#index'
end
app/controllers/securetoken_controller.rb
:
class SecuretokenController < ApplicationController
def index
flussonic = 'http://flussonic-ip'
secret = 'SECRETKEY'
streamname = params[:id]
lifetime = 3600 * 3
starttime = Time.now.to_i - 300
endtime = Time.now.to_i + lifetime
salt = rand(8**8).to_s(8)
hash = Digest::SHA1.hexdigest(streamname + request.remote_ip + starttime.to_s + endtime.to_s + secret + salt)
token = hash + '-' + salt + '-' + endtime.to_s + '-' + starttime.to_s
@url = flussonic + '/' + streamname + '/' + 'embed.html?token=' + token
end
end
app/views/securetoken/index.html.erb
:
<iframe allowfullscreen style="width:640px; height:480px;" src="<%= @url %>"></iframe>