Server side. Registration and authorization

0

For further development of the editor, it is necessary to create the server side of the application. For backend development I used Node.js, Express and MongoDB database.

The first step in the implementation was the creation of registration and authorization on the site.

The implementation is pretty straightforward. The startup file connects middlewares and connects to the database.

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()

Created routes with / register ’,‘ / login ’and‘ / logout ’/ endpoints.

To check the correctness of filling in the form fields, I use the ‘express-validator’ library, it is added to the router as middleware.

I used the ‘bcryptjs’ library to encrypt the password, and the ‘jsonwebtoken’ library to create a token. I store the token on the client in cookies, with the “httpOnly” flag, so that there is no access to it from 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;

When loading the application, it checks if the user is logged in.

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;

The full server side can be viewed at https://github.com/Dragon3DGraff/TertiusAxis_server

0