Щелкните здесь, чтобы опубликовать эту статью в LinkedIn »

Демонстрацию обсуждаемых здесь принципов можно найти http://vue-auth0-demo.s3-website.eu-central-1.amazonaws.com . Также для наглядности в этой статье опущены некоторые детали. Исходный код более полного примера (демонстрация выше) можно найти по адресу https://github.com/sellomkantjwa/vue-auth0-demo .

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

Если у вас есть приложение, в котором пользователь вряд ли будет непрерывно в сети более 2 часов (TTL по умолчанию для токена доступа auth0), вы можете просто позволить токену истечь и попросить пользователя снова войти в систему, если он хотели бы продолжить сеанс за пределами TTL. Я лично не одобряю этот подход - представьте сценарий, в котором пользователь входит в ваше приложение, использует его в течение 10 минут, переключается на новую вкладку, через некоторое время возвращается в ваше приложение и начинает щелкать мышью. Внезапно в середине сеанса токен истекает, и им предоставляется экран входа в систему - не круто. Давайте посмотрим, как мы можем гарантировать, что этого никогда не произойдет.

Самый простой способ работать с Auth0 в браузере - загрузить их SDK.

используя npm:

npm i auth0-js -SE 

или разместите скрипт на своей странице:

<script src=”https://cdn.auth0.com/js/auth0/9.3.1/auth0.min.js"></script>

Управление сеансом пользователя не слишком сложно, его можно резюмировать следующим образом:

  1. Когда пользователь впервые входит в наше приложение, мы фиксируем и сохраняем:
    * access_token (для правильного использования Auth0 и Oauth нам нужно это для аутентификации на нашем API / сервере)
    * expires_in (который говорит нам, сколько времени до истечения срока действия токена)
  2. Мы планируем setTimeout на несколько минут до истечения срока действия токена, чтобы обновить токен.
  3. Когда пользователь в следующий раз заходит в наше приложение, мы проверяем, входил ли он в систему раньше; если они есть, мы проверяем, истек ли срок их действия или скоро истечет, и отправляем их на страницу входа в систему, если это так. Если срок действия токена не истек && не близок к истечению, мы просто впускаем их и планируем обновление на тот момент, когда срок действия токена приближается к истечению.

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

//session-manager.js

//Irrelevant code omitted for clarity
 
import {WebAuth} from "auth0-js";

const auth0 = new WebAuth({
    responseType: "token id_token",
    domain: process.env.DEMO_AUTH0_DOMAIN,
    clientID: process.env.DEMO_AUTH0_CLIENT_ID,
    redirectUri: "http://localhost:8080/login-callback"
});
export{auth0}
//irrelevant code omitted

Обратите внимание, что мы храним наш домен и clientID как настраиваемые переменные. Вы можете жестко их закодировать, если хотите.

Теперь компонент входа в систему.

Вы увидите, что все, что мы здесь делаем, это вызываем auth0.authorize(), который перенаправляет пользователя на нашу страницу, размещенную на Auth0, где они смогут войти. Эта страница выглядит примерно так:

Как только пользователь войдет в систему, он будет перенаправлен на наш назначенный URL-адрес, где мы сможем извлечь и сохранить токен. В приведенной выше настройке (session-manager.js) мы назначили URI http: // localhost: 8080 / login-callback (убедитесь, что URL-адрес в списке разрешенных URL-адресов обратного вызова в Auth0, иначе все это взорвется.)

Давайте соберем и сохраним токен пользователя в назначенном uri перенаправления.

Когда мы перенаправляемся на http: // localhost: 8080 / login-callback, загружается указанный выше компонент. Его единственная цель - собрать, проанализировать и сохранить возвращенные токены. Когда auth0 возвращается к URL-адресу обратного вызова, он добавляет необходимый токен и срок действия к хешу в URL-адресе. Весь URL-адрес выглядит примерно так:

http://localhost:8080/login-callback#access_token=xxxxxxxxxxxxxxxxxxxxxxxxx&expires_in=7200&token_type=Bearer&state=xxxxxxxxxxxxxxxxx&id_token=xxxxxxxxxxxxxxxxxxxxxxxx

Мы используем модуль querystring для синтаксического анализа данных токена в JSON для облегчения обработки, а затем передаем их в мутацию Vuex для хранения в нашем центральном состоянии. Анализируемые данные токена выглядят примерно так:

{
  "access_token":"xxxxxxxxxxxxxxxxx",
  "expires_in":"7200",
  "token_type":"Bearer",
  "state":"xxxxxxxxxxxxxxxxx",
  "id_token":"xxxxxxxxxxxxxx"
}

Затем в нашем хранилище Vuex мы можем сохранить наши токены в центральном состоянии и localstorage. Нам нужно сохранить токен в localstorage, чтобы мы могли сохранять его при перезагрузке страницы или при последующих посещениях сайта до истечения срока действия токена. Таким образом, мы можем повторно использовать токен вместо того, чтобы просить пользователя входить в систему каждый раз, когда он попадает в приложение. Ниже приведен фрагмент нашего магазина, в котором мы определяем мутацию, которая отвечает за сохранение токенов.

Отлично, теперь мы сохранили наши учетные данные и можем настроить геттеры, чтобы мы могли получать их, когда нам нужно. Вот полный магазин:

Теперь мы хотим настроить обновление токенов, чтобы пользователь не выходил из активного сеанса, мы также хотим правильно инициализировать сеанс, когда пользователь заходит в приложение. Давайте перенесем всю эту логику в session-manager.js.

//session-manager.js

Функция initSession выполняет следующие действия:

  1. Проверьте, есть ли у нас дата истечения срока действия токена, если нет, это означает, что пользователь никогда не входил в систему. Мы перенаправляем пользователя на страницу входа.
  2. Если есть срок годности токена, мы проверяем его, чтобы проверить, истек ли он или истечет в следующие 10 минут. Если какое-либо из вышеупомянутых условий выполняется, мы перенаправляем пользователя для входа в систему. 10 минут - это всего лишь буфер, который мы позволяем себе обновить токен. На самом деле это может произойти в любое время до истечения срока действия токена.
  3. Если 1 и 2 не удерживаются, мы знаем, что токен все еще действителен, и мы можем использовать его еще некоторое время. На этом этапе мы настраиваем setTimeout для обновления токена за 10 минут до его фактического истечения.

Функция refreshToken, что неудивительно, фактически обновляет токен. Метод для этого в sdk auth0 называется checkSession Механику того, как Auth0 делает это без перенаправления, можно найти здесь - интересный подход. После обновления токена мы устанавливаем еще один тайм-аут для повторного обновления кнопки за 10 минут до истечения срока его действия.

Нам нужно вызвать initSession при загрузке приложения, чтобы настроить сеанс. Лучшее место для этого - наш корневой компонент Vue, App.vue:

//App.vue

//irrelevant code omitted
<script>

    import Router from "./router";
    import Store from "./store";
    import {initSession} from "./session-manager";

    export default {
        name: 'app',
        data() {
            return {};
        },
        mounted() {
            initSession();  //Initialize our session
        },
        router: Router,
        store: Store
    };


</script>
//irrelevant code omitted

Я оставлю выход из приложения пользователю. (Подсказка: вызовите метод выхода из системы Auth0 sdk, очистите локальное хранилище токенов и очистите время ожидания токена обновления)

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