Mozilla Persona система аутентификации

В этой статье мы увидим, как использовать новую систему аутентификации  Mozilla Persona . Как говорит само название, Persona создана при финансовой поддержке Фонда Mozilla и представляет из себя более простую и безопасную альтернативу OpenID и OAuth.

Mozilla Persona

Mozilla Persona создана по технология BrowserID. Вы можете найти подробности в статье Как работает BrowserID, а здесь мы сосредоточимся на ключевых моментах.

  • Адрес электронной почты, удостоверяющий личность , это проверка поставщика услуг электронной почты (таких как Gmail, Yahoo, и т.д.), кто выступает в роли Primary Identity Authority (или просто primary).
  • Аутентификация выполняется в браузере. Аутентификация со сторонних сайтов не выполняется, так что это эффективная защита конфиденциальности. Браузер имеет роль Реализация Провайдера (IP)..

По идее в будущем, разработчики браузеров реализуют по умолчанию navigator.id API и поставщики услуг электронной почты могут действовать как основной орган для своих пользователей. Мы можем реализовать функциональный рабочий процесс сегодня с помощью реализации HTML5 с Mozilla и сервером browserid.org в качестве резерва идентичности адресов электронной почты.

Давайте предположим, что Артур хочет зарегистрироваться на сайте myfavoritebeer.org с помощью электронной почты mr.arthur@gmail.com. Для этого есть три шага:

1. Сертификат безопасности

Если это первый раз, когда адрес электронной почты будет использоваться в качестве личности, браузер посылает «Введите символы с картинки» для безопасной аутентификации на странице Gmail. Затем браузер генерирует пару ключей (с помощью navigator.id.genKeyPair() ) и отправляет открытый ключ, для Gmail.

Gmail возвращает сертификат обратно, подписанный пакет содержит адрес электронной почты открытого ключа пользователя и дату истечения срока действия. Сертификат подписан и закрыт ключом Gmail и упакован в JSON веб-Token (JWT).
Сертификат и связка ключей хранятся в браузере navigator.id.registerVerifiedEmail() используется в следующей аутентификации.

Если поставщик услуг электронной почты изначально не поддерживает BrowserID, электронная почта проверяется сервером browserid.org в качестве дополнительного варианта. В принципе, вы получите электронное письмо с ссылкой для подтверждения вашей личности.

2. Генерация утверждения

Браузер генерирует утверждение, пакет JWT доказывает, что Артур владеет почтой mr.arthur@gmail.com. Пакет содержит целевой сайт (myfavoritebeer.org), срок годности и сертификат выданный Gmail. Это все подписано с закрытым ключом и отправляется в myfavoritebeer.org для проверки.

Если браузер изначально не поддерживает BrowserID, то операция выполняет резервный код JavaScript предоставленный Mozilla.

3. Подтверждение проверки

Сайт myfavoritebeer.org получает и проверяет запрос Артура. Сначала он проверяет срок действия, открытого ключа GMail, чтобы проверить сертификат. Свидетельство содержит знаки общего используемого ключа, чтобы проверить это утверждение.

Этот шаг предполагает, что Gmail поддерживает BrowserID и утверждает открытые ключи. В настоящее время сертификат содержит свойство, перенаправлять в резерв.

Если все пойдет хорошо, Артур войдёт на сайт и срок подтверждения истечет.

Добавить Mozilla Persona на свой сайт

Следующий пример использует и распространяет информацию и код из официальных источников Mozilla Persona Quick Setup. Кнопки, использующие стили CSS созданы для Sawyer Hollenshead. Код для примера можно скачать с GitHub account. .

Вот основной файл index.php:



<?php
// Check if the user is logged in
$user = null;
if (!ipty($_COOKIE['auth'])) {
    $user = $_COOKIE['auth'];
}
?>
<!DOCTYPE html>
<html>
 <head>
  <meta charset="utf-8">
  <title>Я пью пиво - Mozilla Persona код теста</title>
  <link rel="stylesheet" href=
http://pixelcom.crimea.ua/"css/persona/persona-buttons.css">
 </head>
 <body>
  <h1>Я пью пиво: пробную страницу для Mozilla Persona</h1>
<?php
if (!ipty($user)) {
?>
  Привет <b><?=$user?></b>!
  <a href=
http://pixelcom.crimea.ua/"#" class="persona-button persona-signout"><span>Выйти</span></a>
<?php
}
else {
?>
  <a href=
http://pixelcom.crimea.ua/"#" class="persona-button persona-signin"><span>Вход с Persona</span></a>
<?php
}
?>
  <!--jQuery Library from Google-->
<script src=
http://pixelcom.crimea.ua/"//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>

  <!--Persona Library from Mozilla-->
<script src=
http://pixelcom.crimea.ua/"https://login.persona.org/include.js"></script>

  <!-- Our custom code -->
<script src=
http://pixelcom.crimea.ua/"js/mfb.js"></script>
</body>
</html>


Я буду хранить информацию аутентификации (только адреса электронной почты) в cookie переменной auth. Первые несколько PHP линии проверят этот файл cookie и установка локальной переменной $user , соответственно.
Переменная $user проверяется в body: если пользователь вошел в систему отображается приветственное сообщение, а после кнопка «Выйти».

В нижней части страницы Вы можете найти библиотеку JQuery, Mozilla Persona, и наш собственный код JavaScript файла mfb.js. В этом файле установлены обычные хаки, ссылающиеся для сервера Persona API.



(function(window, $, undefined) {
    // See: http://www.quirksmode.org/js/cookies.html
    window.readCookie = function(name) {
        var nameEQ = name + '=';
        var ca = document.cookie.split(';');
        for(var i = 0; i < ca.length; i++) {
            var c = ca[i];
            while (c.charAt(0) == ' ') {
                c = c.substring(1, c.length);
            }
            if (c.indexOf(nameEQ) == 0) {
                return c.substring(nameEQ.length, c.length);
            }
        }
        return null;
    };

    // Read auth info (the iail address) from cookie
    var currentUser = window.readCookie('auth');

    // If the user is not logged in set the default to null
    if (!currentUser) {
        currentUser = null;
    }

    // The returned value must be URL-decoded
    if (currentUser != null) {
        currentUser = decodeURIComponent(currentUser);
    }

    navigator.id.watch({
        loggedInUser: currentUser,
        onlogin: function(assertion) {
            // A user has logged in! Here you need to send the
            // assertion to your backend for verification and to
            // create a session and then update your UI.
            $.ajax({
                type: 'POST',
                url: 'login.php', // This is a URL on your website.
                data: {assertion: assertion},
                success: function(res, status, xhr) {
                    window.location.reload();
                },
                error: function(xhr, status, err) {
                    alert('Login failure: ' + err);
                }
            });
        },
        onlogout: function() {
            // A user has logged out! Here you need to tear down the
            // user's session by redirecting the user or making a call
            // to your backend. Also, make sure loggedInUser will get
            // set to null on the next page load.
            $.ajax({
                type: 'POST',
                url: 'logout.php', // This is a URL on your website.
                success: function(res, status, xhr) {
                    window.location.reload();
                },
                error: function(xhr, status, err) {
                    alert('Logout failure: ' + err);
                }
            });
        }
    });

    $(document).ready(function(){

        $('a.persona-signin').click(function(e) {
            navigator.id.request();
            e.preventDefault();
        });
        $('a.persona-signout').click(function(e) {
            navigator.id.logout();
            e.preventDefault();
        });
    });
})(window, jQuery);


Во-первых, существует функция, быстрая утилита которая читает cookies. Потом пытается читать currentUser переменной из cookie. Это URL, чтобы мы могли воспользоваться встроенной функция decodeURIComponent() для получения не зашифрованного адреса электронной почты. Важно, что эта переменная содержит либо пользователя, адрес электронной почты или JavaScript значение null; любое другое значение будет вызывать бесконечные перезагрузки цикла.

Далее требуются действия onlogin и onlogout, вызвав navigator.id.watch(API) и, проходя мимо подробности нашей PHP backend. В login.php и logout.php скрипты вызываются через Ajax POST на этот API

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

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

Основной поток:



<?php
// Call the BrowserID API
$response = PersonaVerify();

// If the authentication is successful set the auth cookie
$result = json_decode($response, true);
if ('okay' == $result['status']) {
    $iail = $result['iail'];
    setcookie('auth', $iail);
}

// Print the response to the Ajax script
echo $response;


Сначала он вызывает нужную функцию, которая инкапсулирует всю логику (мы увидим это в ближайшее время). Если в случае положительной проверки, то auth «cookie» будет установлен и в других post-auth, код должен быть назван здесь; в любом случае raw JSON возвращает ответ на вызов скрипта.

Функция PersonaVerify() отвечает за утверждение и проверки сертификатов. Хорошо, что этот шаг выполняется на стороне сервера, чтобы ограничить возможности ввода вредоносного кода. Обычно в этой функции мы должны получить общий ключ от личности и проверить это самому, но поскольку технические характеристики находятся в стадии разработки и протокол BrowserID, не реализованных услуг электронной почты, безопасный способ сделать выполнить удаленную проверку с проверкой службы Persona.



<?php
function PersonaVerify() {
    $url = 'https://verifier.login.persona.org/verify';

    $assert = filter_input(
        INPUT_POST,
        'assertion',
        FILTER_UNSAFE_RAW,
        FILTER_FLAG_STRIP_LOW|FILTER_FLAG_STRIP_HIGH
    );

    $schie = 'http';
    if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != "on") {
        $schie = 'https';
    }
    $audience = sprintf(
        '%s://%s:%s',
        $schie,
        $_SERVER['HTTP_HOST'],
        $_SERVER['SERVER_PORT']
    );

    $params = 'assertion=' . urlencode($assert) . '&audience='
        . urlencode($audience);

    $ch = curl_init();
    $options = array(
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => 2,
        CURLOPT_POSTFIELDS => $params
    );

    curl_setopt_array($ch, $options);
    $result = curl_exec($ch);
    curl_close($ch);
    return $result;
}


Этот код для этой функции от разработчиков Mozilla Persona.

Утверждение параметра берется из jax POSTed. Если посмотреть параметр является, по сути, адрес нашего сайта в виде схемы: //host:port, так что это, рассчитанное с использованием суперглобальным $_SERVER .
Оба параметра кодируются и передаются с использованием HTTP POST CURL вызов службы проверки Persona. Результатом является строка JSON, которая возвращается в вызывающий сценарий для разбора.

В заключение

Благодаря резервному варианту кода, мы может начать использовать систему аутентификации для браузеров. Для более подробной инструкции читайте документацию Persona, которая объясняет различия между Persona и OpenID.

2 комментария на тему “Mozilla Persona система аутентификации”

  1. комментарии

    Здравствуйте. Спасибо за пример. Но у меня никак не выходит один момент. Все вроде бы работает, но всегда почему-то при загрузке страницы вызывается функция той кнопки, которая на данный момент присутствует. Например, если пользователь вошел, значит, на странице отображается кнопка «Выход». При загрузке страницы она почему-то сама активируется и вызывается функция onlogout.
    А если поставить в onlogout еще и перезагрузку, как в примере, то страница бесконечно будет перезагружаться: загружается, вызывается функция onlogout, перезагружается, вызывается onlogout, перезагружается…
    Почему так?

  2. комментарии

    Извините что не немного непонятно описан пример.

    Важно, что бы эта переменная содержала адрес электронной почты пользователя или JavaScript значение null; любое другое значение будет вызывать бесконечные перезагрузки цикла.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML -теги и атрибуты: <a href= http://pixelcom.crimea.ua/"" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>