Поиск по сайту:

Реализация аутентификации пользователей в приложениях Express


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

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

Вы можете реализовать простую модель аутентификации пользователя в Node.js, используя Express, Bcrypt и MongoDB, всего за несколько шагов.

Шаг 1. Настройка среды разработки

Сначала создайте папку проекта и cd в нее, выполнив:

mkdir user-authentication
cd user-authentication

Затем инициализируйте npm в каталоге вашего проекта, выполнив:

npm init -y

Флаг -y инициализирует npm и создает файл package.json со всеми настройками по умолчанию.

Эта модель аутентификации пользователя требует нескольких зависимостей.

Они включают:

  • Express: Express — это платформа Node.js, предоставляющая надежный набор функций для веб-приложений и мобильных приложений. Это упрощает создание серверных приложений с помощью Node.js.
  • Bcrypt: bcrypt — это пакет npm, реализующий функцию хеширования паролей bcrypt. Он позволяет создавать хеши из простых строк паролей.
  • Mongoose: Mongoose — это библиотека моделирования объектных данных MongoDB. Это упрощает взаимодействие между вашим приложением и базой данных MongoDB.
  • dotenv: dotenv — это пакет с нулевой зависимостью, который загружает переменные среды из файла .env в process.env.
  • Валидатор: валидатор — это пакет, который содержит различные функции проверки строк.
  • Body-parser: пакет body-parser анализирует тела запросов в промежуточном программном обеспечении перед вашими обработчиками.

Установите пакеты, запустив:

npm install express bcrypt mongoose dotenv validator body-parser

Затем создайте файл app.js в корневом каталоге вашего проекта и добавьте приведенный ниже блок кода, чтобы создать базовый сервер Express:

// app.js
const express = require('express');
const app = express();
const bodyParser = require("body-parser");
 
const port = 3000;
 
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
 
app.listen(port, ()=>{
    console.log(`App is listening on port ${port}`);
});

Этот код создает экземпляр экспресс-приложения путем вызова экспресс-функции. Затем он использует промежуточное программное обеспечение body-parser для анализа тел входящих запросов. Затем он начинает прослушивать трафик на порту 3000, вызывая метод прослушивания экспресс-экземпляра и передавая переменную порта в качестве аргумента.

Шаг 2. Подключение вашего приложения к базе данных

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

Затем перейдите к файлу app.js и импортируйте mongoose:

const mongoose = require("mongoose");

Затем вызовите import dotenv и вызовите для него метод config:

require("dotenv").config();

Вызов метода config в dotenv загружает переменные среды в process.env.

Наконец, вызовите метод подключения в mongoose и передайте свой URI MongoDB в качестве аргумента:

mongoose.connect(process.env.MONGODB_URI).then(() => {
    console.log('Connected to Database Successfully')
})

Шаг 3. Создание модели пользователя

В корневом каталоге вашего проекта создайте папку «models»; здесь вы будете хранить свою модель мангуста:

mkdir models

Затем создайте файл «userModel» и добавьте следующий импорт:

const mongoose = require('mongoose')
const { isEmail } = require('validator')

isEmail — это функция проверки, которая возвращает true, если заданная строка является электронным письмом. Он понадобится вам, чтобы применить проверку mongoose к вашей пользовательской модели.

Затем добавьте следующий код в файл userModel:

// models/userModel
const userSchema = mongoose.Schema({
    email: {
        type: String,
        required: [true, 'Email is required'],
        validate: {
            validator: isEmail,
            message: props => `${props.value} is not a valid email`
        }
    },
 
    password: {
        type: String,
        required: [true, 'Password is required'],
        validate: {
            validator: function (value) {
                return value.length >= 6
            },
            message: () => 'Password must be at least six characters long'
        }
    }
})
 
module.exports = mongoose.model('User', userSchema)

В приведенном выше коде создается переменная userSchema, в которой хранится значение метода mongoose.Schema. Метод mongoose.Schema сопоставляет свойства коллекции MongoDB и определяет форму документов внутри нее. Схема mongoose имеет два свойства — адрес электронной почты и пароль, которые будут вашими требованиями аутентификации.

Свойство электронной почты имеет строковый тип и для параметра обязательно установлено значение true. Сопутствующее сообщение об ошибке «Требуется адрес электронной почты» будет отображаться, если тело запроса не содержит свойства email. Наконец, используя пользовательскую проверку mongoose, свойство validator ссылается на функцию isEmail. Эта функция возвращает true или false в зависимости от действительности строки как электронного письма. Затем свойство message принимает значение адреса электронной почты (props) и создает значимое сообщение об ошибке.

Свойство пароля представляет собой обязательную строку с сообщением об ошибке «Требуется пароль». Функция валидатор является анонимной и возвращает true, если длина пароля составляет не менее шести символов.

Последняя строка создает и экспортирует модель mongoose, вызывая метод model для mongoose. Передайте имя модели (Пользователь) в качестве первого аргумента и схема (userSchema) в качестве второго аргумента.

Шаг 4. Реализация маршрутов входа и регистрации

В корневом каталоге вашего проекта создайте папку routes:

mkdir routes

В папке маршрутов создайте файл userRoutes.js и добавьте следующий импорт:

// routes/userRoutes.js
const express = require("express");
const User = require("../models/userModel");
const bcrypt = require("bcrypt");

Создайте экземпляр Express Router, вызвав метод Router в express:

const router = express.Router();

Затем создайте маршрут регистрации, добавив приведенный ниже блок кода в файл userRoute.js:

router.post("/sign-up", async (req, res) => {
  try {
    // Extract email and password from the req.body object
    const { email, password } = req.body;
    
    // Check if the email is already in use
    let userExists = await User.findOne({ email });
 
    if (userExists) {
      res.status(401).json({ message: "Email is already in use." });
      return;
    }
 
    // Define salt rounds
    const saltRounds = 10;
 
    // Hash password
    bcrypt.hash(password, saltRounds, (err, hash) => {
      if (err) throw new Error("Internal Server Error");
 
      // Create a new user
      let user = new User({
        email,
        password: hash,
      });
 
      // Save user to database
      user.save().then(() => {
        res.json({ message: "User created successfully", user });
      });
    });
  } catch (err) {
    return res.status(401).send(err.message);
  }
});

В приведенном выше блоке кода сначала вы деструктурировали адрес электронной почты и пароль из объекта req.body. Затем проверьте, использует ли пользователь уже этот адрес электронной почты, поскольку он должен быть уникальным для каждого пользователя. Если адрес электронной почты уже использовался, вы возвращаетесь и останавливаете выполнение кода с кодом состояния 401.

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

Используя bcrypt, вы хэшировали свой пароль пользователя, вызывая метод хеширования bcrypt. Метод хеширования принимает три параметра: хэшируемую строку, соляные раунды и функцию обратного вызова. Вы передаете пароль пользователя, созданную ранее переменную saltRounds и обратный вызов.

Соляные раунды относятся к времени, необходимому для расчета одного хеша bcrypt. Чем выше количество раундов соли, тем больше раундов хеширования.

Если хеш-метод выдает ошибку, вы выдаете «внутреннюю ошибку сервера». В противном случае вы устанавливаете для свойства пароля успешный хэш и сохраняете его в своей базе данных, вызывая метод save в экземпляре User.

Затем создайте маршрут входа, добавив приведенный ниже блок кода в файл userRoute.js:

router.post("/sign-in", async (req, res) => {
  try {
    // Extract email and password from the req.body object
    const { email, password } = req.body;
 
    // Check if user exists in database
    let user = await User.findOne({ email });
 
    if (!user) {
      return res.status(401).json({ message: "Invalid Credentials" });
    }
 
    // Compare passwords
    bcrypt.compare(password, user.password, (err, result) => {
      if (result) {
        return res.status(200).json({ message: "User Logged in Successfully" });
      }
      
      console.log(err);
      return res.status(401).json({ message: "Invalid Credentials" });
    });
  } catch (error) {
    res.status(401).send(err.message);
  }
});
 
module.exports = router;

В приведенном выше блоке кода сначала вы деструктурируете адрес электронной почты и пароль из объекта req.body. Затем вы проверяете, существует ли пользователь в вашей базе данных. Если пользователь не существует в вашей базе данных, вы вернетесь с кодом состояния 401.

Затем, используя метод сравнения bcrypt, передайте пароль, предоставленный пользователем, и хешированный пароль, который вы получили из своей базы данных. Сравните их, чтобы убедиться, что они совпадают. Если пароли совпадают, вы возвращаете код состояния 200 и сообщение об успехе. В противном случае вы вернете код состояния 401 и сообщение об ошибке.

Наконец, импортируйте router в файл app.js и используйте его в качестве промежуточного программного обеспечения уровня приложения.

Это завершает вашу модель аутентификации пользователя; теперь пользователи могут безопасно зарегистрироваться и войти в ваше приложение.

Важность аутентификации пользователя

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

Статьи по данной тематике: