Conor
Conor

Reputation: 740

How to implement Node.JS model using Sequelize

I have a project with the below Model, Controller, and Route File for user. I am wanting to implement sequelize, which I have managed to partially achieve using the account files below, however, I am struggling to work out how to implement logging in and ensuring a request has a valid token usijng user.ensureToken which would become account.ensureToken.

I'm fairly new to Node.Js so I'm not even sure where to start

user.model.js

const bcrypt = require('bcrypt');

const sql = require("./db.js");
const HashBits = require("../config/auth.config.js");
const faker = require('faker');

// constructor
const User = function(user) {
    this.first_name = user.first_name;
    this.last_name = user.last_name;
    this.mob_no = user.mob_no;
    this.user_name = user.user_name;
    this.password = user.password;
};

User.create = (newUser, result) => {
    bcrypt.hash(newUser.password, HashBits.saltRounds, (err, hash) => {
        newUser.password = hash;
        sql.query("INSERT INTO users SET ?", newUser, (err, res) => {
            if (err) {
                // console.log("error: ", err);
                result(err, null);
                return;
            }
            newID = res.insertId;
            // console.log("created user: ", { id: res.insertId, ...newUser });
            result(null, { id: res.insertId, ...newUser });
        });
        
    });
};

User.authenticate = (user,result) => {
    // sql.query(`SELECT * FROM customers WHERE id = ${customerId}`, (err, res) => {
    sql.query(`SELECT * FROM users WHERE user_name = '${user.user_name}'`, (err, res) => {
        // sql.query("SELECT * FROM users ", (err, res) => {
        if (err) {
            // console.log("error: ", err);
            result(err, null);
            return;
        }
        if(res.length !== 1){
            // console.log("error: found multiple users");
            result("error: found multiple users", null);
            return;
        }
        
        // console.log("Found user: ",res[0]);
        bcrypt.compare(user.password, res[0].password, function(err, res2) {
            if(res2){
                // console.log("Yes");
                result(null,res[0]);
            }else{
                // console.log("On ya bike");
                result("ERROR",null);
                // return;
            }
        });
    });
};
module.exports = User;

user.controller.js

const User = require("../models/user.model.js");

var jwt = require("jsonwebtoken");

const config = require("../config/auth.config.js");

// Create and Save a new User
exports.create = (req, res) => {
  // Validate request
  if (!req.body) {
    res.status(400).send({
      message: "Content can not be empty!"
    });
  }
  
  // Create a User
  const user = new User({
    first_name: req.body.first_name,
    last_name: req.body.last_name,
    mob_no: req.body.mob_no,
    user_name: req.body.user_name,
    password: req.body.password
  });
  
  // Save User in the database
  User.create(user, (err, data) => {
    if (err)
    res.status(500).send({
      message:
      err.message || "Some error occurred while creating the User."
    });
    else res.send(data);
  });
};

exports.authenticate = (req,res) => {
  
  if (!req.body) {
    res.status(400).send({
      message: "Content can not be empty!"
    });
  }
  
  const user = new User({
    user_name: req.body.user_name,
    password: req.body.password
  });
  
  User.authenticate(user, (err,data) => {
    if(err)
    res.status(500).send({
      message:
      err.message || "Some error occurred while authenticating the User."
    });
    else {
      var token = jwt.sign({ id: user.id }, config.secret, {
        expiresIn: 86400 // 24 hours
      });
      // res.send(data);
      
      res.status(200).send({
        id: data.id,
        username: data.user_name,
        accessToken: token
      });
    }
  });
};

exports.ensureToken = (req, res, next) => {
  let token = req.headers["x-access-token"];
  
  if (!token) {
    return res.status(403).send({
      message: "No token provided!"
    });
  }
  
  jwt.verify(token, config.secret, (err, decoded) => {
    if (err) {
      return res.status(401).send({
        message: "Unauthorized!"
      });
    }
    req.userId = decoded.id;
    next();
  });
}

user.routes.js

module.exports = app => {
    const users = require("../controllers/user.controller.js");
    // Create a new User
    app.post("/User", users.create);
    // Login
    app.post("/User/Login", users.authenticate);

  };

account.model.js

const bcrypt = require("bcrypt");


module.exports = (sequelize, Sequelize) => {
    const Account = sequelize.define("account", {
        firstName: {
            type: Sequelize.STRING
        },
        username: { 
            type: Sequelize.STRING
        },
        password: {
            type: Sequelize.STRING,
            set(value){
                const hash = bcrypt.hashSync(value, 10);
                this.setDataValue('password', hash);
            }
        }
    });

    return Account;
};

account.controller.js

const db = require("../models");
const Account = db.accounts;
const Op = db.Sequelize.Op;

var jwt = require("jsonwebtoken");

const config = require("../config/auth.config.js");

// Create and Save a new New
exports.create = (req, res) => {

    // Validate request
if (!req.body.username) {
    res.status(400).send({
    message: "Content can not be empty!"
    });
    return;
}

// Create a Site
const account = {
    firstName: req.body.firstName,
    username: req.body.username,
    password: req.body.password
};

Account.create(account)
.then(data => {
    res.send(data);
})
.catch(err => {
    res.status(500).send({
    message:
    err.message || "Some error occurred while creating the Account."
    });
});
};

exports.authenticate = (req,res) => {

    if (!req.body) {
        res.status(400).send({
        message: "Content can not be empty!"
        });
    }
    
    const account = new Account({
        username: req.body.username,
        password: req.body.password
    });

};

account.routes.js

module.exports = app => {
    const accounts = require("../controllers/account.controller.js");
    
    var router = require("express").Router();

    app.post("/account", accounts.create);

    app.post("/account/Login", accounts.authenticate);

};

Upvotes: 0

Views: 158

Answers (1)

Aryan
Aryan

Reputation: 3626

you need to use jwt token for access token as you said and you are bcrypt password in model file which will be security issue you have to bcrypt password as soon as it comes in request I have implemented it in my answer remove code of password bcrypt from your model file

you have to import in your account.controller.js

  const db = require("../models");
  const User = db.user;
  require('dotenv').config();
  const Op = db.Sequelize.Op;
  const errors = require('../config/errors');
  const error = errors.errors;

  var jwt = require("jsonwebtoken");
  var bcrypt = require("bcryptjs");

 module.exports = {
 signup: async (req, res) => {
 if (!req.body.first_name|| !req.body.lastt_name || !req.body.password) {

  return res.status(200).send(error.MANDATORY_FIELDS);
}
try {
  // Save User to Database
  User.create({
    name: req.body.name,
    email: req.body.email,
    mo_no: req.body.mo_no,
    city: req.body.city,
    password: bcrypt.hashSync(req.body.password, 8),
    user_type: "admin"
  }).then(function (user) {
 
        return res.status(200).send(error.OK)
  })
    .catch(function (err) {
      console.log(err);
      return res.status(500).send(error.SERVER_ERROR)
    });
} catch (e) {
  console.log(e);
  return res.status(500).send(error.SERVER_ERROR)
}
},

signin: async (req, res) => {
if (!req.body.email || !req.body.password) {
  return res.status(200).send(error.MANDATORY_FIELDS);
}
User.findOne({
  where: {
    email: req.body.email
  }
}).then(function (user) {
  if (!user) {
    return res.status(404).send(error.USER_NOT_PRESENT);
  }

  const passwordIsValid = bcrypt.compareSync(
    req.body.password,
    user.password
  );

  if (!passwordIsValid) {
    return res.status(422).send(error.PASSWORD_MISSMATCH, {
      accessToken: null
    });
  }

  const token = jwt.sign({ id: user.id, first_name: user.first_name }, 
  process.env.secret, {
    expiresIn: 86400 // 24 hours
  });

  const authorities = [];
    return res.status(200).send({
      id: user.id,
      name: user.name,
      email: user.email,
      accessToken: token
    });
  });
})
  .catch(function (err) {
    console.log(err)
    return res.status(500).send(error.SERVER_ERROR);
  });
 }
}

than you have to create a separate folder for authorization like authorize.js or authJwt.js where you have to check is token is valid or not put this code in authorize.js

at decoding time secret token or password also needed which you have in .env file

const jwt = require("jsonwebtoken");

 verifyToken = (req, res, next) => {
 let token = req.headers["x-access-token"];

if (!token) {
  return res.status(403).send(error.TOKEN_NOT_PROVIDED);
}

jwt.verify(token, process.env.secret, (err, decoded) => {
 if (err) {
  return res.status(401).send(error.UNAUTHORIZED);
 }
 req.first_name= decoded.first_name;
 req.id = decoded.user_id
 next();
 });
};

const authJwt = {
  verifyToken: verifyToken
};
module.exports = authJwt;

than you have to import authorize.js file in your routes whenever you want like this

const authorize = require('../authorize.js');

module.exports = app => {
    const accounts = require("../controllers/account.controller.js");

     var router = require("express").Router();

     app.post("/account",  accounts.create);

     app.post("/account/Login", 
     authorize.verifyToken,accounts.authenticate);

};

it will be more effective if you genreate access token at signin time

Upvotes: 1

Related Questions