Подтвердить что ты не робот

Заголовок авторизации HTTP в EventSource (События, отправленные сервером)

Мне нужно установить заголовок авторизации в EventSource HTML5. Поскольку события, отправленные сервером, кажется, не используются, поскольку появились веб-узлы, я не могу найти какую-либо полезную документацию. Подход, который я уже нашел, заключается в передаче данных авторизации в URL-адресе... но мне этот метод не нравится.

Я использую AngularJS и устанавливаю перехватчики на $httpProvider, но EventSource не перехватывается AngularJS, поэтому я не могу добавить заголовок.

4b9b3361

Ответ 1

EventSource не имеет API для отправки заголовков HTTP на сервер. Я тоже пытался справиться с этой проблемой, когда создавал в реальном времени чат с использованием SSE.

Однако я думаю, что файлы cookie будут отправляться автоматически, если ваш SSE-сервер является тем же сервером, что и ваш сервер аутентификации.

Ответ 2

Этот polyfill добавляет поддержку заголовка авторизации: https://github.com/Yaffle/EventSource/

Итак, вы можете сделать:

new EventSource("https://domain/stream", { authorizationHeader: "Bearer ..." });

Ответ 3

Я понимаю, что ваш пост был более года назад, но я оказался в одной лодке с хорошими ответами. Я надеюсь, что это может помочь кому-то или хотя бы дать им некоторые идеи...

Файлы cookie кажутся достаточно легкими, но что происходит, если кто-то блокирует файлы cookie? Я бы попросил их включить файлы cookie для использования сайта. В этот момент они начинают задаваться вопросом, могут ли они доверять сайту, так как они отключили куки для "соображений безопасности". Все время я хочу, чтобы файлы cookie включались по соображениям безопасности!

Используя AJAX, можно легко получить данные аутентификации POST через SSL, но это невозможно с помощью SSE. Я видел много сообщений, где люди тогда говорят: "Просто используйте querystring", но я не хочу нарушать безопасность клиента, отправляя данные аутентификации в виде простого текста (example.com/stream?sessionID=idvalue), который кто-то может snoop.

После того, как я провел пару часов в мозгу, я понял, что могу выполнить общую цель без ущерба для данных пользователя клиента. Чтобы уточнить, я не обнаружил способ POST при установлении соединения EventSource, но он позволяет браузеру безопасно передавать токен аутентификации с EventSource каждый раз, когда он повторно соединяется. Ключ их состоит в том, чтобы получить желаемый идентификатор сессии/токена в lastEventID.

Пользователь может аутентифицироваться, как обычно, с помощью имени пользователя/пароля (или AJAX POSTing токена, который вы храните в localstorage). Процесс auth AJAX будет передавать объект JSON с коротким токеном (истекает через 60 секунд или когда он используется), который будет сохранен в вашем желаемом бэкэнд (например, mySQL) вместе с более длинным токеном. На этом этапе вы инициируете свое SSE-соединение, например:

    qString = "?slt=" + "value-that-expires-within-seconds";
    streamURL = "http://example.com/stream.php";
    var streamSource = new EventSource(streamURL + qString);

    streamSource.addEventListener('auth',function(e) {
        var authStatus = JSON.parse(e.data);
        if (authStatus.session !== 'valid') {
            qString = "";
            streamSource.close();
        }
    })

В соответствующем PHP вы сделаете что-то вроде этого:

        header("Content-Type: text/event-stream\n");
        ob_end_flush();
        ob_start();

        if (isThisShortLivedTokenValid($_GET["slt"])) {
            // The short-lived-token is still valid... so we will lookup
            // the value of the corresponding longer-lasting token and
            // IMMEDIATELY invalidate the short-lived-token in the db.
            sendMsg($realToken,'auth','session','valid');
            exit;
        } else if (isThisRealTokenValid($_SERVER["HTTP_LAST_EVENT_ID"])){
            while (1) {
                // normal code goes here
                // if ($someCondition == 'newDataAvailable') sendMsg($realToken,'chat','msg-id','msg-content');
            }
        } else {
            http_response_code(404); // stop the browser from reconnecting.
            exit; //quit the PHP скрипт and don't send anything.
        }


        function sendMsg($id, $event, $key, $val) {
            echo "{" . PHP_EOL;
            echo "event: " . $event . PHP_EOL;
            echo "id: $id" . PHP_EOL;
            echo 'data: {"' . $key . '" : "' . $val . '"}' . PHP_EOL;
            echo "}" . PHP_EOL;
            echo PHP_EOL;
            ob_flush();
            flush();
        }

        function isThisShortLivedTokenValid($sltValue) {
            //stuff to connect to DB and determine if the
            //value is still valid for authentication
            return $dbResult == $sltValue ? TRUE : FALSE;
        }

SSE подключается к короткоживущему токену, PHP проверяет на краткосрочный токен и удаляет его из БД, поэтому он больше не сможет снова использовать AUTH. Это несколько похоже на то, когда вы получаете текстовый код из 6 цифр для входа в онлайн-банкинг. Мы используем PHP для толкания REAL-токена (который истекает намного позже), который мы извлекли из базы данных как идентификатор события. Для Javascript не нужно ничего делать с этим событием - сервер автоматически завершит соединение, но вы можете прослушать это событие, если хотите сделать больше с ним.

На этом этапе соединение SSE закончилось, так как PHP закончил script. Однако браузер автоматически восстановит соединение (обычно с 3 секундами). На этот раз он отправит lastEventId... который мы установили для значения токена, прежде чем мы сбросили соединение. В следующем соединении это значение будет использоваться как наш токен, и приложение будет работать как ожидалось. Не обязательно отключать соединение, пока вы начинаете использовать реальный токен в качестве идентификатора события при отправке сообщений/событий. Это значение токена передается полностью зашифрованным по SSL как при его получении браузером, так и при каждом последующем подключении к серверу. Значение, которое было передано "в ясности", истекло в течение нескольких секунд с момента его получения и использования, и оно больше не может использоваться кем-либо, кто его обнаруживает. Если кто-то попытается использовать его, он получит 404 RESPONSE.

Если вы уже используете идентификатор потока событий для какой-либо другой цели, это может не работать "из коробки", если вы не объедините токен аутентификации и ранее использованное значение и не разделите его на переменные, чтобы он был прозрачным для остальные приложения. Что-то вроде:

    // when sending data, send both values
    $sseID = $token_value . "_" . $previouslyUsedID;
    sendMsg($sseID,'chat','msg-id','msg-content');

    // when a new connection is established, break apart the values
    $manyIDs = explode("_", $_SERVER["HTTP_LAST_EVENT_ID"])
    $token_value = $manyIDs[0]
    $previouslyUsedID = $manyIDs[1]

Ответ 4

другой способ передать токен авторизации через URL-адрес в качестве параметра запроса, но вы должны учитывать безопасность. Также добавьте поддержку авторизации через параметр запроса на стороне сервера.

Ответ 5

Если вы используете эту вилку источника событий polyfill, вы сможете добавить заголовки авторизации аналогично тому, как описывает rafaelzlisboa: https://github.com/AlexGalays/EventSource#923b9a0998fcfd7753040e09aa83764b3cc0230d

Ï не знаю, можете ли вы предоставить заголовок аутентификации в качестве второго аргумента, например, в примере rafaelzlisboa, я получил его для работы, создав объект заголовков и разместив там заголовок авторизации следующим образом:

new EventSource("https://domain/stream", { headers: { Authorization: Bearer.... }});