Автор: Мэри Окосун

Каждая серверная служба, ориентированная на пользователя, такая как Strapi, зависит от аутентификации и управления пользователями, поскольку у разных пользователей могут быть разные роли и разрешения. Strapi — это автономная система управления контентом (CMS) с открытым исходным кодом, которая дает разработчикам свободу использовать свои любимые инструменты и фреймворки во время разработки.

Зачем аутентифицировать ваше приложение Strapi?

Разрешая только аутентифицированным пользователям (или процессам) доступ к своим защищенным ресурсам, аутентификация позволяет организациям поддерживать безопасность своих сетей. Аутентификация — это процесс подтверждения того, что физическое или юридическое лицо на самом деле является тем, за кого оно себя выдает.

Предпосылки

Чтобы следовать в этом руководстве по проекту:

  • Вам необходимо скачать и установить Node.js (версии 16.x рекомендуются Strapi).
  • Вам необходимо иметь npm (только версия 6) или yarn для запуска сценариев установки CLI.
  • Вам необходимо иметь базовые знания JavaScript и Vue.js.

Цели

В этом руководстве рассказывается, как добавить пользователя в качестве типа контента, как протестировать аутентифицированного пользователя и почему вам необходимо аутентифицировать пользователя. Вы узнаете, как реализовать токен обновления для аутентифицированного пользователя. Вы также узнаете, как создать мини-приложение с использованием Vue.js, фреймворка JavaScript и Strapi, которое демонстрирует, как аутентифицированный пользователь может получить доступ к панели инструментов, создав для этого пользователя токен обновления. В конце этого руководства вы должны знать, как создать функцию токена обновления в приложении Strapi.

Бэкэнд-реализация

Вы будете использовать Strapi для реализации серверной части. Это будет сделано в несколько шагов:

1. Создание шаблона проекта Strapi Вы будете запускать проект Strapi локально и использовать сценарии установки Strapi CLI (интерфейс командной строки), так как это самый быстрый способ запустить Strapi локально. Новый экземпляр Strapi, strapi-refresh-token-backend, будет создан в указанном каталоге на вашем компьютере.

npx create-strapi-app strapi-refresh-token-backend --quickstart
        #OR
        yarn create-strapi-app strapi-refresh-token-backend --quickstart

В указанном вами каталоге приведенные выше фрагменты кода создадут новый проект Strapi. Он должен автоматически открыть http://localhost:1337/admin/auth/register-admin в вашем браузере. Если нет, вы можете запустить панель администратора в своем браузере, выполнив следующую команду в своем терминале.

npm run develop
        # OR
        yarn run develop

Чтобы зарегистрироваться в качестве нового администратора системы, откроется новое окно.

Вы можете заполнить форму и нажать кнопку отправки. После этого вы будете перенаправлены в панель администратора.

2. Создать нового пользователя На панели администратора Strapi перейдите к диспетчеру контента и в типе коллекции пользователей вы создадите новую запись для пользователя.

Заполните следующие данные в форме:

  • имя пользователя: маринуар
  • электронная почта: [email protected]
  • пароль: *****************

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

3. Тестирование аутентифицированного пользователя в API-клиенте. Здесь вы будете тестировать нового пользователя в Postman. Вы можете использовать клиент API по вашему выбору; однако в этом руководстве Postman будет использоваться для тестирования конечных точек API. Перейдите к своему клиенту Postman и отправьте запрос POST на http://localhost:1337/api/auth/local. Тело ответа должно быть примерно таким:

{
            "identifier": "marynoir",
            "password": "marynoir"
        }
  • Идентификатор: это может быть либо электронная почта пользователя, либо имя пользователя.
  • Пароль: это пароль пользователя

Тело ответа должно быть примерно таким:

{
            "jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNjYxOTQ0OTQ4LCJleHAiOjE2NjQ1MzY5NDh9.yeYcS8kA_TI9JqVn4Xnqu0lKiT4BUgnM7l8HFKJ56hc",
            "user": {
                "id": 1,
                "username": "marynoir",
                "email": "[email protected]",
                "provider": "local",
                "confirmed": true,
                "blocked": false,
                "createdAt": "2022-08-31T11:22:24.613Z",
                "updatedAt": "2022-08-31T11:22:24.613Z"
            }
        }

4. Знакомство с функцией Refresh Token Из ответа, полученного выше, вы можете увидеть jwt в тексте ответа. Токен jwt может использоваться для выполнения запросов API с ограниченным доступом. В этом руководстве токен jwt будет использоваться для предоставления пользователю доступа к приложению, и когда срок действия токена истечет, доступ пользователей будет ограничен. Пользователю будет предложено запросить другой токен jwt с помощью функции токена обновления, чтобы снова получить доступ к приложению. Вы создадите токен обновления, настроив некоторые папки и файлы в каталоге Strapi.

  • Шаг 1. В файле .env добавьте следующие переменные среды:
// .env
    
    REFRESH_SECRET=strapisecret
    REFRESH_TOKEN_EXPIRES=2d
    JWT_SECRET_EXPIRES=360s
    NODE_ENV=development
  • Шаг 2. В папке src/extensions создайте папку с именем users-permissions. В этой папке создайте еще одну папку с именем controllers/validation. Внутри этой папки создайте файл auth.js. Добавьте следующие фрагменты кода в файл auth.js: // ../users-permissions/controllers/validation/auth.js
  • 'use strict'; const { yup, validateYupSchema } = require('@strapi/utils'); const callbackBodySchema = yup.object().shape({ identifier: yup.string().required(), password: yup.string().required(), }); module.exports = { validateCallbackBody: validateYupSchema(callbackBodySchema) };
The code above creates a schema, `callbackBodySchema`, that requires an identifier and password for the login authentication. This authentication is similar to the Strapi login system.

- **Step 3:** In the `users-permissions` folder, create a new folder called `utils`. Within this folder, create a file called `index.js` and add the following code snippets to the file:
```js
        // ../users-permissions/utils/index.js
    
        'use strict';
        const getService = name => {
          return strapi.plugin('users-permissions').service(name);
          return
        };
        module.exports = {
          getService,
        };
  • Шаг 4. В папке users-permissions создайте новый файл с именем strapi-server.js. Добавьте следующие фрагменты кода в файл strapi-server.js:
// ../users-permissions/strapi-server.js
    
        const utils = require('@strapi/utils');
        const { getService } = require('../users-permissions/utils');
        const jwt = require('jsonwebtoken');
        const _ = require('lodash');
        const {
            validateCallbackBody
        } = require('../users-permissions/controllers/validation/auth');
    
        const { setMaxListeners } = require('process');
        const { sanitize } = utils;
        const { ApplicationError, ValidationError } = utils.errors;
        const sanitizeUser = (user, ctx) => {
            const { auth } = ctx.state;
            const userSchema = strapi.getModel('plugin::users-permissions.user');
            return sanitize.contentAPI.output(user, userSchema, { auth });
        };
    
        module.exports = (plugin) => {
         return plugin
        }
  • Шаг 5. На следующем шаге вы будете использовать существующую процедуру входа в систему от Strapi, которую можно найти в папке node-modules под @strapi/plugin-users-permissions/server/controllers/auth.js.

Добавьте следующие фрагменты в функцию module.export:

// ../users-permissions/strapi-server.js
    
        module.exports = (plugin) => {
            plugin.controllers.auth.callback = async (ctx) => {
                const provider = ctx.params.provider || 'local';
                const params = ctx.request.body;
                const store = strapi.store({ type: 'plugin', name: 'users-permissions' });
                const grantSettings = await store.get({ key: 'grant' });
                const grantProvider = provider === 'local' ? 'email' : provider;
                if (!_.get(grantSettings, [grantProvider, 'enabled'])) {
                    throw new ApplicationError('This provider is disabled');
                }
                if (provider === 'local') {
                    await validateCallbackBody(params);
                    const { identifier } = params;
                    // Check if the user exists.
                    const user = await strapi.query('plugin::users-permissions.user').findOne({
                        where: {
                            provider,
                            $or: [{ email: identifier.toLowerCase() }, { username: identifier }],
                        },
                    });
                    if (!user) {
                        throw new ValidationError('Invalid identifier or password');
                    }
                    if (!user.password) {
                        throw new ValidationError('Invalid identifier or password');
                    }
                    const validPassword = await getService('user').validatePassword(
                        params.password,
                        user.password
                    );
                    if (!validPassword) {
                        throw new ValidationError('Invalid identifier or password');
                    } else {
                         ctx.send({
                            jwt: getService('jwt').issue({
                                id: user.id,
                            }),
                            user: await sanitizeUser(user, ctx),
                        });
                    }
                    const advancedSettings = await store.get({ key: 'advanced' });
                    const requiresConfirmation = _.get(advancedSettings, 'email_confirmation');
                    if (requiresConfirmation && user.confirmed !== true) {
                        throw new ApplicationError('Your account email is not confirmed');
                    }
                    if (user.blocked === true) {
                        throw new ApplicationError('Your account has been blocked by an administrator');
                    }
                    return ctx.send({
                        jwt: getService('jwt').issue({ id: user.id }),
                        user: await sanitizeUser(user, ctx),
                    });
                }
                // Connect the user with a third-party provider.
                try {
                    const user = await getService('providers').connect(provider, ctx.query);
                    return ctx.send({
                        jwt: getService('jwt').issue({ id: user.id }),
                        user: await sanitizeUser(user, ctx),
                    });
                } catch (error) {
                    throw new ApplicationError(error.message);
                }
            }
            return plugin
        }

Приведенный выше код проверяет, используется ли для аутентификации при входе поставщик Strapi, такой как Google или Auth0. В этом руководстве вы не используете внешний поставщик, поэтому переменная поставщика будет local.

Если поставщик является локальным, он подтвердит существование пользователя с помощью поля идентификатор. Если пользователь существует, он проверит, совпадает ли пароль в теле запроса с паролем, использованным при регистрации. Если пароль совпадает, пользователь входит в систему.

  • Шаг 6. Вам потребуется файл cookie обновления, который будет использоваться вместе с токеном jwt для создания нового токена обновления. Вам нужно добавить следующие фрагменты кода чуть ниже функции sanitizeUser в файле strapi-server.js:
// ../users-permissions/strapi-server.js
        const sanitizeUser = (user, ctx) => {
           ...
        };
    
        // issue a JWT
        const issueJWT = (payload, jwtOptions = {}) => {
            _.defaults(jwtOptions, strapi.config.get('plugin.users-permissions.jwt'));
            return jwt.sign(
                _.clone(payload.toJSON ? payload.toJSON() : payload),
                strapi.config.get('plugin.users-permissions.jwtSecret'),
                jwtOptions
            );
        }
    
        // verify the refreshToken by using the REFRESH_SECRET from the .env
        const verifyRefreshToken = (token) => {
            return new Promise(function (resolve, reject) {
                jwt.verify(token, process.env.REFRESH_SECRET, {}, function (
                    err,
                    tokenPayload = {}
                ) {
                    if (err) {
                        return reject(new Error('Invalid token.'));
                    }
                    resolve(tokenPayload);
                });
            });
        }
    
        // issue a Refresh token
        const issueRefreshToken = (payload, jwtOptions = {}) => {
            _.defaults(jwtOptions, strapi.config.get('plugin.users-permissions.jwt'));
            return jwt.sign(
                _.clone(payload.toJSON ? payload.toJSON() : payload),
                process.env.REFRESH_SECRET,
                { expiresIn: process.env.REFRESH_TOKEN_EXPIRES }
            );
        }

В строках 7–14 функция issueJWT создает новый токен jwt, который будет использоваться при запросе токена обновления.

В строках 17–29 функция verifyRefreshToken используется для проверки того, что токен обновления, переданный в теле запроса при запросе нового jwt, действительно действителен. Он использует функцию jwt.verify() для проверки допустимости токена с токеном REFRESH_SECRETin the .env file. If this is valid, it returns a new token for the user, else it returns an errorInvalid`.

В строках 32–39 функция issueRefreshToken используется для создания нового токена обновления, который будет храниться в файле cookie.

Теперь, когда вы можете создать токен обновления, вам нужно сохранить этот токен обновления в файлах cookie. Замените содержимое проверки isValidPassword следующими фрагментами кода. Фрагменты задают токен обновления с именем refreshToken в качестве имени файла cookie, если пароль действителен.

// ../users-permissions/strapi-server.js
    
        if (!validPassword) {
          throw new ValidationError('Invalid identifier or password');
        } else {
            ctx.cookies.set("refreshToken", issueRefreshToken({ id: user.id }), {
                httpOnly: true,
                secure: false,
                signed: true,
                overwrite: true,
        });
            ctx.send({
              status: 'Authenticated',
              jwt: issueJWT({ id: user.id }, { expiresIn: process.env.JWT_SECRET_EXPIRES }),
              user: await sanitizeUser(user, ctx),
            });
        }
  • Шаг 7. Давайте проверим, что вы уже сделали. На этом этапе вы смогли провести рефакторинг системы входа в наше приложение. Если зарегистрированный пользователь входит в систему, у него должен быть токен jwt, а также токен обновления, сохраненный в файлах cookie. Вы можете отправить запрос POST на маршрут API входа в систему http://localhost:1337/api/auth/local и увидеть refreshToken, сохраненный в файлах cookie.

  • Шаг 8. Следующим шагом является создание функции, которая будет принимать токен обновления и выдавать пользователю новый jwt. Добавьте фрагменты кода под функцией plugin.controllers.auth.callback:
// ../users-permissions/strapi-server.js
    
        plugin.controllers.auth.callback = async (ctx) => {
            ......
        }   
        plugin.controllers.auth['refreshToken'] = async (ctx) => {
                const store = await strapi.store({ type: 'plugin', name: 'users-permissions' });
                const { refreshToken } = ctx.request.body;
                const refreshCookie = ctx.cookies.get("refreshToken")
    
                if (!refreshCookie && !refreshToken) {
                    return ctx.badRequest("No Authorization");
                }
                if (!refreshCookie) {
                    if (refreshToken) {
                        refreshCookie = refreshToken
                    }
                    else {
                        return ctx.badRequest("No Authorization");
                    }
                }
                try {
                    const obj = await verifyRefreshToken(refreshCookie);
                    const user = await strapi.query('plugin::users-permissions.user').findOne({ where: { id: obj.id } });
                    if (!user) {
                        throw new ValidationError('Invalid identifier or password');
                    }
                    if (
                        _.get(await store.get({ key: 'advanced' }), 'email_confirmation') &&
                        user.confirmed !== true
                    ) {
                        throw new ApplicationError('Your account email is not confirmed');
                    }
                    if (user.blocked === true) {
                        throw new ApplicationError('Your account has been blocked by an administrator');
                    }
                    const refreshToken = issueRefreshToken({ id: user.id })
                    ctx.cookies.set("refreshToken", refreshToken, {
                        httpOnly: true,
                        secure: false,
                        signed: true,
                        overwrite: true,
                    });
                    ctx.send({
                        jwt: issueJWT({ id: obj.id }, { expiresIn: process.env.JWT_SECRET_EXPIRES }),
                        refreshToken: refreshToken,
                    });
                }
                catch (err) {
                    return ctx.badRequest(err.toString());
                }
            }

Фрагменты выше получают refreshToken из файлов cookie и сохраняют их как refreshCookie. Если refreshCookie не найдено, возвращается ошибка No Authorization. Если refreshCookie найдено, оно проверяется с помощью созданного ранее verifyRefreshToken(). Выполняются проверки, например, существует ли пользователь, не подтверждена ли электронная почта пользователя и заблокирована ли учетная запись пользователя. Он создает новый jwt, используя issueJWT(), и назначает его пользователю.

  • Шаг 9. Последний шаг — создать маршрут API для обновления нашего jwt и запроса нового токена. Добавьте следующий код перед оператором return plugin:
// ../users-permissions/strapi-server.js
    
        plugin.controllers.auth.callback = async (ctx) => {
            ......
        }
        plugin.controllers.auth['refreshToken']= async (ctx) => {
            ......
        } 
        plugin.routes['content-api'].routes.push({
                method: 'POST',
                path: '/token/refresh',
                handler: 'auth.refreshToken',
                config: {
                    policies: [],
                    prefix: '',
                }
        });

Давайте проверим, что вы уже сделали. Вы можете отправить запрос POST на маршрут API токена обновления http://localhost:1337/api/token/refresh и увидеть новый jwt и refreshToken в теле ответа.

По умолчанию Strapi предоставляет токен проверки (jwt), действительный в течение 30 дней. Для целей этого проекта вы должны вручную настроить дату истечения срока действия, чтобы наше приложение можно было протестировать быстрее. Создайте файл plugins.js в папке config и добавьте следующие фрагменты кода:

// config/plugins.js
    
        module.exports = ({ env }) => ({
            'users-permissions': {
              enabled: true,
              config: {
                jwt: {
                  expiresIn: '15m',
                },
              },
            },
          });

Реализация внешнего интерфейса

Вы создали серверные службы и настроили функцию токена обновления; Следующим шагом является создание внешнего приложения для использования API-интерфейсов Strapi с Vue.js. Фронтенд-приложение будет представлять собой мини-приложение с двумя (2) экранами: вход в систему и интерфейс панели управления. Зарегистрированный пользователь может войти в систему и быть перенаправленным на экран панели инструментов. Когда срок действия токена такого пользователя истечет, пользователю будет предложено запросить другой токен. Если пользователь не запросит новый токен, он выйдет из приложения.

Согласно документации, Vue.js — это JavaScript-фреймворк для создания пользовательских интерфейсов. Он строится на основе стандартных HTML, CSS и JavaScript и предоставляет декларативную модель программирования на основе компонентов, которая помогает эффективно разрабатывать пользовательские интерфейсы, будь то простые или сложные. Чтобы создать новый проект Vue.js, выполните следующие действия:

  1. Перейдите в каталог и установите пакет Vue.js с помощью команды:
npm install -g @vue/cli
    # OR
    yarn global add @vue/cli
  1. Create a new project using the command:
vue create strapi-refresh-token-frontend

Вам будет предложено выбрать пресет. Выберите «ручной выбор функций», чтобы выбрать нужные функции. Вы бы выбрали Vuex, Router и Lint/Formatter. Vuex — это библиотека управления состоянием для приложений Vue; Маршрутизатор позволяет изменить URL без перезагрузки страницы, а Lint/Formatter корректно форматирует коды.

После успешного создания проекта перейдите в каталог папки и запустите приложение:

cd strapi-refresh-token-frontend
    npm run serve
    #OR
    yarn run serve

URL-адрес http://localhost:8080/ должен открыть ваше приложение Vue.js в вашем браузере.

Установка зависимостей

Вам нужно установить некоторые зависимости, такие как axios. Axios — это зависимость пакета, которая будет использоваться для вызова внутренних API Strapi:

npm install axios

Во-первых, удалите файл HelloWorld.vue в папке компонентов, файлы HomeView.vue и AboutView.vue в папке представлений, так как эти файлы являются избыточными в этом проекте.

Создайте два новых файла Login.vue и Dashboard.vue в папке компонентов и скопируйте следующее содержимое в файл login.vue.

//Login.vue
    
        <template>
          <div class="login">
            <input
              type="text"
              v-model="identifier"
              placeholder="Enter username/email"
            />
            <input 
              type="text" 
              v-model="password" 
              placeholder="Enter password" 
            />
            <div>
              <button @click="login">LOGIN</button>
            </div>
          </div>
        </template>
        <script>
        import axios from "axios";
        export default {
          name: "login",
          data() {
            return {
              identifier: "",
              password: "",
            };
          },
          methods: {
            async login() {
              try {
                const data = {
                  identifier: this.identifier,
                  password: this.password,
                };
                const options = {
                  credentials: "include",
                  withCredentials: true,
                };
                const res = await axios.post(
                  "http://localhost:1337/api/auth/local",
                  data,
                  options
                );
                localStorage.setItem("token", res.data.jwt);
                localStorage.setItem("user", JSON.stringify(res.data.user));
                if (res.status === 200) {
                  this.$router.push("/dashboard");
                }
              } catch (err) {
                console.log(err);
              }
            },
          },
        };
        </script>
        <style scoped>
        .login {
          display: flex;
          flex-direction: column;
          padding: 35px;
          background: #e8e8e8;
        }
        input {
          padding: 15px;
          margin: 5px 0;
          border-radius: 2px;
          border: 1px solid white;
        }
        button {
          background: #36865d;
          color: white;
          border: none;
          padding: 15px 25px;
          width: 100%;
          margin-top: 5px;
          font-weight: bolder;
        }
        button:hover {
          background: #4cab7a;
        }
        </style>

В файл Dashboard.vue добавьте следующее содержимое:

<template>
          <div>
            <h1>User Dashboard</h1>
            <ul>
              <li><b>Username:</b> {{ getUser.username }}</li>
              <li><b>Email:</b> {{ getUser.email }}</li>
              <li><b>Is User Confirmed:</b> {{ getUser.confirmed }}</li>
              <li><b>Is User Blocked: </b>{{ getUser.blocked }}</li>
              <li><b>Provider:</b> {{ getUser.provider }}</li>
            </ul>
          </div>
        </template>
        <script>
        export default {
          name: "dashboard",
          computed: {
            getUser() {
              let jwtPayload = JSON.parse(localStorage.getItem("user"));
              return jwtPayload;
            },
          },
        };
        </script>
        <style scoped>
        ul {
          list-style-type: none !important;
          padding: 0;
        }
        </style>

В папке представлений создайте файл LoginView.vue и скопируйте следующее содержимое:

<template>
          <div class="container">
            <Login />
          </div>
        </template>
        <script>
        import Login from "@/components/Login.vue";
        export default {
          name: "LoginView",
          components: {
            Login,
          },
        };
        </script>
        <style scoped>
        .container {
          margin: 50px auto;
          width: 400px;
        }
        </style>

Будет создано модальное окно, которое появится, когда срок действия токена истечет, и попросит пользователя выбрать, должно ли приложение обновлять токен или нет. В папке компонентов создайте файл Modal.vue и скопируйте следующие фрагменты кода:

<template>
          <div class="modal-overlay" @click="$emit('close-modal')">
            <div class="modal" @click.stop>
              <h6>Token Expired!</h6>
              <p>You are unable to view your dashboard.</p>
              <p>Do you want to refresh your token?</p>
              <button id="no-button" @click="handleNoButton">No</button>
              <button id="yes-button" @click="getRefreshToken">Yes</button>
            </div>
          </div>
        </template>
        <script>
        import axios from "axios";
        export default {
          methods: {
            handleNoButton() {
              this.$router.push("/");
            },
            async getRefreshToken() {
              try {
                const data = {
                  refreshToken: localStorage.getItem("token"),
                };
                const options = {
                  "Access-Control-Allow-Credentials": true,
                  withCredentials: true,
                };
                const res = await axios.post(
                  "http://localhost:1337/api/token/refresh",
                  data,
                  options
                );
                localStorage.setItem("token", res.data.jwt);
                this.$emit("close-modal");
              } catch (err) {
                console.log(err);
              }
            },
          },
        };
        </script>
        <style scoped>
        .modal-overlay {
          position: fixed;
          top: 0;
          bottom: 0;
          left: 0;
          right: 0;
          display: flex;
          justify-content: center;
          background-color: #000000da;
        }
        .modal {
          text-align: center;
          background-color: white;
          height: 200px;
          width: 400px;
          margin-top: 10%;
          padding: 60px 0;
          border-radius: 20px;
        }
        .close {
          margin: 10% 0 0 16px;
          cursor: pointer;
        }
        .close-img {
          width: 25px;
        }
        .check {
          width: 150px;
        }
        h6 {
          font-weight: 500;
          font-size: 28px;
          margin: 20px 0;
        }
        p {
          font-size: 16px;
        }
        button {
          width: 100px;
          height: 40px;
          color: white;
          font-size: 14px;
          border-radius: 12px;
          margin-top: 10px;
          margin-right: 10px;
          border: 1px solid #fff;
        }
        #yes-button {
          background-color: #4cab7a;
        }
        #no-button {
          background-color: #ba0000da;
        }
        </style>

Рефакторинг файла index.js в соответствии с внесенными изменениями. Это должно быть похоже на следующее:

import { createRouter, createWebHistory } from "vue-router";
        import LoginView from "../views/LoginView.vue";
        const routes = [
          {
            path: "/",
            name: "login",
            component: LoginView,
          },
          {
            path: "/dashboard",
            name: "dashboard",
            // route level code-splitting
            // this generates a separate chunk (about.[hash].js) for this route
            // which is lazy-loaded when the route is visited.
            component: () =>
              import(/* webpackChunkName: "about" */ "../views/Dashboard.vue"),
          },
        ];
        const router = createRouter({
          history: createWebHistory(process.env.BASE_URL),
          routes,
        });
        export default router;

Тестирование приложения

Теперь вы можете протестировать интерфейсную реализацию приложения. Перейдите на http://localhost:8080/, и вы должны увидеть страницу входа.

Введите имя пользователя и пароль, которые были созданы для пользователя в записи серверной части Strapi. Если данные верны, вы будете перенаправлены на страницу панели инструментов.

Когда срок действия токена истекает, всплывает модальное окно.

Если вы нажмете кнопку Нет, приложение направит вас обратно на страницу входа, чтобы вы могли снова войти в систему и создать новый токен. Если вы нажмете кнопку Да, приложение сделает вызов API к API токена обновления и автоматически повторно выпустит новый jwt и токен обновления. Это позволяет вам продолжать просмотр приложения без необходимости каждый раз входить в систему. Чтобы убедиться, что это действительно работает, вы можете проверить refreshToken, хранящийся в файле cookie, и токен, хранящийся в файле localstorage. При каждом нажатии кнопки Да создается новый refreshToken.

Заключение

В этом руководстве вы узнали, как добавить и аутентифицировать пользователя с помощью jwt. Была проведена демонстрация того, как реализовать токен обновления для аутентифицированного пользователя с использованием jwt из действия входа пользователя.

Вы можете скачать исходный код для фронтенда и бэкенда реализации с Github.