Серверная часть. Регистрация и авторизация
Для дальнейшего развития редактора необходимо создание серверной части приложения. Для разработки серверной части я использовал Node.js, Express и базу данных MongoDB.
Первым шагом реализации стало создание регистрации и авторизации на сайте.
Реализация довольно проста. Стартовый файл подключает middlewares и подключается к базе данных.
const express = require('express');
const config = require('config');
const mongoose = require('mongoose');
const cookieParser = require('cookie-parser');
const path = require('path');
const app = express();
app.use(cookieParser());
app.use(express.json({ extended: true }));
app.use('/api/check', require('./routes/checkAuth.routes'));
app.use('/api/auth', require('./routes/auth.routes'));
const PORT = config.get('port');
if (process.env.NODE_ENV === 'production') {
app.use('/', express.static(path.join(__dirname, 'client')))
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'index.html'))
})
}
async function start() {
try {
await mongoose.connect(config.get('mongoURI'), {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true
})
app.listen(PORT, () => console.log(`Server has been started at ${PORT}`))
} catch (error) {
console.log('Server error', error.message);
process.exit(1);
}
}
start()
Создал роуты с эндпойнтами /register’, ‘/login’ и ‘/logout’/.
Для проверки правильности заполнения полей формы использую библиотеку ‘express-validator’, она добавляется в роутер как middleware.
Для шифрования пароля использовал библиотеку ‘bcryptjs’, для создания токена библиотеку ‘jsonwebtoken’. Токен на клиенте храню в cookies, с флагом “ httpOnly ”, чтобы не было доступа к нему из Javascript.
const { Router } = require('express');
const router = Router();
const config = require('config');
const User = require('../models/User');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const {check, validationResult} = require('express-validator');
router.post('/register',
[
check('name', 'Enter name').exists(),
check('email', "Incorrect email").isEmail(),
check('password', 'Min password length is 6 symbols').isLength({ min: 6 })
],
async (req, res) => {
try {
const errors = validationResult(req);
if(!errors.isEmpty()){
return res.status(400).json({
errors: errors.array(),
message: 'Incorrect registration data'
})
}
const {name, email, password} = req.body;
const candidate = await User.findOne({ email })
if (candidate) {
return res.status(400).json({ message: 'User is already exist' })
}
const hashedPassword = await bcrypt.hash(password, 12);
const user = new User({ name, email, password: hashedPassword });
await user.save();
res.status(201).json({ message: 'Account created!' });
} catch (error) {
res.status(500).json({ message: "ERROR"})
console.log(error);
}
})
router.post(
'/login',
[
check('email', "Incorrect email").normalizeEmail().isEmail(),
check('password', 'Enter password').exists()
],
async (req, res) => {
try {
const errors = validationResult(req);
if(!errors.isEmpty()){
return res.status(400).json({
errors: errors.array(),
message: 'Incorrect registration data'
})
}
const {email, password} = req.body;
const user = await User.findOne({email});
if(!user){
return res.status(400).json({message: 'User not found'});
}
const isMatch = await bcrypt.compare(password, user.password);
if(!isMatch){
return res.status(400).json({message: 'Wrong password'});
}
const token = jwt.sign(
{userId: user.id},
config.get('jwtSecret'),
{expiresIn: '1h'}
)
res.clearCookie('token');
res.cookie('token', token, { httpOnly: true });
res.json( { userId: user.id, userName: user.name });
} catch (error) {
res.status(500).json({ message: "ERROR"})
console.log(error);
}
})
router.post(
'/logout',
async (req, res) => {
try {
res.clearCookie('token');
res.json( { userId: undefined, userName: undefined });
} catch (error) {
res.status(500).json({ message: "ERROR"})
}
})
module.exports = router;
При загрузке приложения выполняется проверка, зарегистрирован ли пользователь.
const { Router } = require('express');
const router = Router();
const config = require('config');
const User = require('../models/User');
const jwt = require('jsonwebtoken');
router.post('/checkAuth',
async (req, res) =>{
try {
const token = req.cookies.token;
if (!token) {
return res.status(401).json({ message: 'No authorization' })
}
const decoded = jwt.verify(token, config.get('jwtSecret'));
if(!decoded.userId){
res.clearCookie('token');
return res.status(400).json({message: 'User not found'});
}
const userId = decoded.userId;
const user = await User.findOne({_id: userId});
if(!user){
res.clearCookie('token');
return res.status(400).json({message: 'User not found'});
}
res.status(200).json( {userId, userName: user.name});
} catch (error) {
res.status(500).json({ message: "ERROR"})
console.log(error);
}
req.cookies
})
module.exports = router;
Полностью серверную часть можно посмотреть на https://github.com/Dragon3DGraff/TertiusAxis_server
