Как добавить аутентификацию в полнофункциональное веб-приложение MERN

Как добавить аутентификацию в полнофункциональное веб-приложение MERN

9 ноября 2022 г.

Эта статья является частью 2 раздела "Давайте создадим и развернем полное стек веб-приложения MERN". В этом руководстве мы создали приложение под названием Productivity Tracker, которое позволяет вам вести журнал своей повседневной деятельности. Однако есть проблема с нашим приложением. Сможете разобраться 👀? Ваша подсказка в названии этой статьи. В этом руководстве мы рассмотрим проблему и способы ее решения.

Начнем

Проблема

Поскольку ваше приложение в настоящее время доступно в Интернете, любой может использовать его и добавлять действия в вашу базу данных. Это нехорошо, не так ли? Здесь на помощь приходит аутентификация. Чтобы предотвратить несанкционированный доступ к вашему приложению, добавьте аутентификацию.

authenticate

Добавление аутентификации

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

Внутренняя аутентификация

Нам нужно внедрить внутреннюю аутентификацию и авторизовать некоторые маршруты.

Аутентификация и авторизация

Эти два слова могут сбить вас с толку. Аутентификация позволяет кому-то с учетными данными получить доступ к нашему приложению, а Авторизация предоставляет доступ к ресурсам авторизованным людям.

authentication vs authorization

В нашем сценарии авторизация предоставляет доступ к таким ресурсам, как создание действий и получение действий, тогда как проверка подлинности предполагает вход в приложение.

Введение в JWT

<цитата>

Веб-токен JSON (JWT) – это компактное безопасное для URL средство представления заявок, которые должны быть переданы между двумя сторонами. Утверждения в JWT кодируются как объект JSON, который используется в качестве полезной нагрузки структуры веб-подписи JSON (JWS) или в качестве открытого текста структуры веб-шифрования JSON (JWE), что позволяет утверждениям быть подписанными в цифровом виде или защищенными от нарушения целостности. с кодом аутентификации сообщения (MAC) и/или в зашифрованном виде.

Проще говоря, JWT используется для проверки наличия у пользователя разрешения на выполнение действия.

Давайте реализуем аутентификацию при входе с помощью JWT.

Поскольку вы единственный человек, использующий ваше приложение, вам не нужна функция регистрации, и вы можете хранить EMAIL и PASSWORD в файле .env. .

* Откройте файл .env и добавьте эти три переменные.

TOKEN_KEY=somesecrettoken
EMAIL=youremail
PASSWORD=yourpassword

Здесь TOKEN_KEY может быть любой случайной строкой. Он используется JWT.

  • Откройте терминал и установите пакет jsonwebtoken.
npm i jsonwebtoken
  • Откройте папку controllers и создайте файл auth.controller.js. Скопируйте и вставьте приведенный ниже код.
const jwt = require("jsonwebtoken");

require("dotenv").config();

const EMAIL = process.env.EMAIL;
const PASSWORD = process.env.PASSWORD;

/* If the email and password are correct, then return a token. */
const login = (req, res) => {
  /* Destructuring the email and password from the request body. */
  const { email, password } = req.body;

  if (email === EMAIL && password === PASSWORD) {
    /* Creating a token. */
    const token = jwt.sign({ email }, process.env.TOKEN_KEY, {
      expiresIn: "2h",
    });
    return res.status(200).json({
      statusCode: 200,
      msg: "Login successful",
      token,
    });
  }
  return res.status(401).json({
    statusCode: 401,
    msg: "Invalid Credentials",
  });
};

module.exports = {
  login,
};

Приведенный выше код проверяет, совпадают ли адрес электронной почты и пароль, и если они совпадают, он создает токен и отправляет его во внешний интерфейс для реализации внешней аутентификации.

  • Откройте папку routes, создайте auth.routes.js и зарегистрируйте новый маршрут для входа в систему.
const express = require("express");

const { login } = require("../controllers/auth.controller");

const router = express.Router();

router.post("/login", login);

module.exports = router;
  • Наконец, в server.js используйте зарегистрированный маршрут.
...
const AuthRouter = require("./routes/auth.route");
...

...
app.use("/api/auth", AuthRouter);
...

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

Давайте создадим промежуточное ПО для авторизации этих маршрутов.

GET /api/activities

POST /api/activity
  • В корне проекта создайте папку с именем middleware, а в этой папке создайте файл auth.js. Скопируйте и вставьте приведенный ниже код.
const jwt = require("jsonwebtoken");

require("dotenv").config();

/* It checks if the token is valid and if it is, it decodes it and attaches the decoded token to the request object */
const verifyToken = (req, res, next) => {
  const token = String(req.headers.authorization)
    .replace(/^bearer|^jwt/i, "")
    .replace(/^s+|s+$/gi, "");

  try {
    if (!token) {
      return res.status(403).json({
        statusCode: 403,
        msg: "A token is required for authentication",
      });
    }
    /* Verifying the token. */
    const decoded = jwt.verify(token, process.env.TOKEN_KEY);
    req.userData = decoded;
  } catch (err) {
    return res.status(401).json({
      statusCode: 401,
      msg: "Invalid Token",
    });
  }
  return next();
};

module.exports = verifyToken;

Мы создали промежуточную функцию под названием verifyToken() для проверки токена, отправленного внешним интерфейсом через заголовок. Если проверка прошла успешно, пользователь может получить доступ к вышеуказанным маршрутам.

  • Теперь откройте activity.route.js и измените код следующим образом.
...
router.get("/activities", auth, getActivities);

router.post("/activity", auth, addActivity);
...

Вот оно! Внутренняя аутентификация выполнена 🎉.

Внешняя аутентификация

Пришло время реализовать внешнюю аутентификацию.

  • Сначала создадим страницу входа.
  • В папке src создайте файлы Login.jsx и Login.css. Скопируйте и вставьте приведенный ниже код в файл Login.jsx и используйте это в Login.css.

```javascript! импортировать React из «реагировать»;

импортировать "./Login.css";

постоянный логин = () => { / Когда пользователь отправляет форму, предотвратить действие по умолчанию, получить адрес электронной почты и пароль из формы, отправить запрос POST на серверную часть с адресом электронной почты и паролем и, если ответ будет успешным, сохранить токен в локальном хранилище и перезагрузите страницу. / const handleSubmit = async (событие) => { событие.preventDefault(); const {адрес электронной почты, пароль} = event.target;

const response = await fetch(
  `${process.env.REACT_APP_BACKEND_URL}/auth/login`,
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      email: email.value,
      password: password.value,
    }),
  }
);

const data = await response.json();
localStorage.setItem("token", data.token);
window.location.reload();

};

возврат (

Войти

<диапазон> <диапазон>
); };

экспортировать логин по умолчанию;

This will render the login page.

 ![login page](https://cdn.hackernoon.com/images/5L1PsURyndeLVm1wIoUdHEN6ZP12-2022-11-08T19:29:01.285Z-cla8lvip1002n0bs6hosu0nht)

The `handleSubmit()` gets the email and password from the form, makes a `POST` request, and sends email and password values for verification. After that server verifies and sends back a token that we can use to access resources.

Here we are using `localStorage` to store the value in the browser permanently so that we won't get logged out after closing the application or browser.

* Open the `index.js` file and add this logic. If there is a token in `localStorage` render `App.jsx` otherwise `Login.jsx`.

```javascript
...
const token = localStorage?.getItem("token");

root.render(
    <React.StrictMode>
    {token ? <App /> : <Login />}
    </React.StrictMode>
);
...
  • Теперь в файле App.jsx нам нужно отправить токен через заголовок, чтобы серверная часть проверила его и предоставила доступ к маршрутам.
...
useEffect(() => {
    const fetchData = async () => {
      const result = await fetch(
        `${process.env.REACT_APP_BACKEND_URL}/activities`,
        {
          headers: {
            Authorization: `Bearer ${token}`, // <----------- HERE
          },
        }
      );
      const data = await result.json();
      setActivities(data);
    };
    fetchData();
}, [token]);
...

...
const addActivity = async (event) => {
    event.preventDefault();

    const newActivity = {
      name: event.target.activity.value,
      time: event.target.time.value,
    };

    await fetch(`${process.env.REACT_APP_BACKEND_URL}/activity`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${token}`, // <---------- HERE
      },
      body: JSON.stringify(newActivity),
    });

    event.target.activity.value = "";
    event.target.time.value = "";
    window.location.reload();
};
...

Готово ✅! Мы внедрили как внешнюю, так и внутреннюю аутентификацию. Теперь только вы можете получить доступ к своему приложению 🥳 (если вы не поделитесь своими учетными данными 👀).

Исходный код: productivity-app


В следующей статье мы научимся писать тесты для фронтенда и бэкенда 😍.


Также здесь


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE