В днешната дигитална ера изграждането на сигурна система за удостоверяване е от съществено значение за всяко уеб приложение. Един от най-популярните начини за изграждане на сигурна система за удостоверяване е използването на NodeJS и MongoDB. В този урок ще преминем през процеса на изграждане на сигурна система за удостоверяване с NodeJS и MongoDB.

Първо, трябва да създадем нов NodeJS проект и да инсталираме необходимите зависимости. Ще използваме ExpressJS като наша уеб рамка и Mongoose като наш MongoDB драйвер. След като сме настроили нашия проект и сме инсталирали зависимостите, можем да започнем да изграждаме нашата система за удостоверяване.

Първата стъпка в изграждането на нашата система за удостоверяване е създаването на потребителски модел в MongoDB с помощта на Mongoose. Ще дефинираме полетата за нашия потребителски модел, включително потребителско име, имейл и парола. Ще добавим и някои допълнителни полета, като датата на създаване на потребителя и датата, на която последно е влязъл.

След това ще създадем нашите маршрути за удостоверяване в ExpressJS. Ще създадем маршрути за регистриране на нов потребител, влизане и излизане. В маршрута за регистрация ще потвърдим въведеното от потребителя и ще създадем нов потребител в MongoDB. В маршрута за влизане ще проверим идентификационните данни на потребителя и ще генерираме JSON уеб токен (JWT), за да удостоверим потребителя.

Ние също така ще създадем междинен софтуер за проверка на JWT в последващи заявки към защитени маршрути. Този междинен софтуер ще провери подписа и датата на изтичане на JWT, като гарантира, че потребителят все още е удостоверен.

И накрая, ще защитим нашето приложение, като добавим криптиране към паролите на нашите потребители. Ще използваме библиотеката bcrypt, за да хешираме и солираме паролата на потребителя, преди да я съхраним в MongoDB.

Следвайки тези стъпки, ние успешно изградихме защитена система за удостоверяване с NodeJS и MongoDB. Нашата система за удостоверяване използва JSON уеб токени (JWT) за удостоверяване, криптира паролите на нашите потребители и проверява JWT при последващи заявки. Това гарантира, че данните на нашите потребители са сигурни и защитени от злонамерени атаки.

Със сигурност! Ето пълен пример за изграждане на защитена система за удостоверяване с NodeJS и MongoDB:

  1. Настройте проекта и инсталирайте зависимости:
mkdir node-auth
cd node-auth
npm init -y
npm i express mongoose bcrypt jsonwebtoken dotenv

2. Създайте .env файл за съхранение на променливи на средата:

touch .env

Добавете следните променливи към файла .env:

MONGODB_URI=mongodb://localhost:27017/node-auth
SECRET_KEY=mysecretkey

3. Създайте db.js файл, за да се свържете с MongoDB:

const mongoose = require('mongoose');
require('dotenv').config();

const connectDB = async () => {
  try {
    await mongoose.connect(process.env.MONGODB_URI, {
      useNewUrlParser: true,
      useUnifiedTopology: true,
      useCreateIndex: true,
      useFindAndModify: false
    });
    console.log('Connected to MongoDB');
  } catch (error) {
    console.log('Error connecting to MongoDB:', error);
  }
};

module.exports = connectDB;

4. Създайте models/User.js файл, за да дефинирате потребителската схема:

const mongoose = require('mongoose');
const bcrypt = require('bcrypt');

const userSchema = new mongoose.Schema(
  {
    username: {
      type: String,
      required: true,
      unique: true
    },
    email: {
      type: String,
      required: true,
      unique: true
    },
    password: {
      type: String,
      required: true
    },
    role: {
      type: String,
      enum: ['user', 'admin'],
      default: 'user'
    }
  },
  { timestamps: true }
);

// Hash the password before saving it to the database
userSchema.pre('save', async function (next) {
  const user = this;
  if (!user.isModified('password')) return next();

  try {
    const salt = await bcrypt.genSalt();
    user.password = await bcrypt.hash(user.password, salt);
    next();
  } catch (error) {
    return next(error);
  }
});

// Compare the given password with the hashed password in the database
userSchema.methods.comparePassword = async function (password) {
  return bcrypt.compare(password, this.password);
};

const User = mongoose.model('User', userSchema);

module.exports = User;

5. Създайте controllers/auth.js файл за обработка на заявки за удостоверяване:

const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
const User = require('../models/User');

// Register a new user
const register = async (req, res, next) => {
  const { username, email, password } = req.body;

  try {
    const hashedPassword = await bcrypt.hash(password, 10);
    const user = new User({ username, email, password: hashedPassword });
    await user.save();
    res.json({ message: 'Registration successful' });
  } catch (error) {
    next(error);
  }
};

// Login with an existing user
const login = async (req, res, next) => {
  const { username, password } = req.body;

  try {
    const user = await User.findOne({ username });
    if (!user) {
      return res.status(404).json({ message: 'User not found' });
    }

    const passwordMatch = await user.comparePassword(password);
    if (!passwordMatch) {
      return res.status(401).json({ message: 'Incorrect password' });
    }

    const token = jwt.sign({ userId: user._id }, process.env.SECRET_KEY, {
      expiresIn: '1 hour'
    });
    res.json({ token });
  } catch (error) {
    next(error);
  }
};

module.exports = { register, login };

6. Създайте файл `middlewares/auth.js` за обработка на мидълуер за удостоверяване:

const jwt = require('jsonwebtoken');
const User = require('../models/User');

const authenticate = async (req, res, next) => {
  const token = req.headers.authorization?.split(' ')[1];

  if (!token) {
    return res.status(401).json({ message: 'Authentication required' });
  }

  try {
    const decodedToken = jwt.verify(token, process.env.SECRET_KEY);
    const user = await User.findById(decodedToken.userId);
    if (!user) {
      return res.status(404).json({ message: 'User not found' });
    }

    req.user = user;
    next();
  } catch (error) {
    res.status(401).json({ message: 'Invalid token' });
  }
};

module.exports = { authenticate };

7. Създайте файл routes/auth.js, за да дефинирате маршрути за удостоверяване:

const express = require('express');
const { register, login } = require('../controllers/auth');

const router = express.Router();

router.post('/register', register);
router.post('/login', login);

module.exports = router;

8. Създайте routes/user.js файл, за да дефинирате потребителски маршрути:

const express = require('express');
const { authenticate } = require('../middlewares/auth');

const router = express.Router();

router.get('/profile', authenticate, (req, res) => {
  res.json({ message: `Welcome ${req.user.username}` });
});

module.exports = router;

9. Създайте index.js файл, за да стартирате сървъра:

const express = require('express');
const connectDB = require('./db');
const authRoutes = require('./routes/auth');
const userRoutes = require('./routes/user');

const app = express();
const PORT = process.env.PORT || 3000;

// Connect to MongoDB
connectDB();

// Parse JSON request body
app.use(express.json());

// Define authentication routes
app.use('/auth', authRoutes);

// Define user routes
app.use('/user', userRoutes);

// Start the server
app.listen(PORT, () => {
  console.log(`Server started on port ${PORT}`);
});

С тази настройка можете да регистрирате нов потребител, като направите POST заявка до /auth/register със следното JSON тяло:

{
  "username": "john.doe",
  "email": "[email protected]",
  "password": "password123"
}

След това можете да влезете със същия потребител, като направите POST заявка до /auth/login със следното JSON тяло:

{
  "username": "john.doe",
  "password": "password123"
}

Сървърът ще отговори с JSON обект, съдържащ токен:

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2MGMwZDQ2NTgzOWM1MTQ2ODZjYzZiYTAiLCJpYXQiOjE2MTkxMzcyNjAsImV4cCI6MTYxOTE0MDg2MH0.wJGkkTz27e_vyaxf1M85rMUPtNvXo25ntGtJgdy-aNk"
}

След това можете да получите достъп до потребителския профил, като направите GET заявка до /user/profile със следната Authorization заглавка:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2MGMwZDQ2NTgzOWM1MTQ2ODZjYzZiYTAiLCJpYXQiOjE2MTkxMzcyNjAsImV4cCI6MTYxOTE0MDg2MH0.wJGkkTz27e_vyaxf1M85rMUPtNvXo25ntGtJgdy-aNk

Сървърът ще отговори с JSON обект, съдържащ приветствено съобщение:

{
  "message": "Welcome john.doe"
}

Този пример показва как можете да изградите сигурна система за удостоверяване с Node.js и MongoDB, използвайки JSON уеб токени. Като следвате стъпките, описани в това ръководство, можете да създадете стабилна система за удостоверяване за вашите собствени Node.js приложения.