added refresh token functionality
This commit is contained in:
parent
adb27445ff
commit
42391cdf7f
|
|
@ -1,3 +1,10 @@
|
|||
module.exports = {
|
||||
secret: "bullpen-secret-key"
|
||||
secret: "bullpen-secret-key",
|
||||
|
||||
// jwtExpiration: 3600, // 1 hour
|
||||
// jwtRefreshExpiration: 86400, // 24 hours
|
||||
|
||||
/* for test */
|
||||
jwtExpiration: 60, // 1 minute
|
||||
jwtRefreshExpiration: 120 // 2 minutes
|
||||
};
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
const db = require("../models");
|
||||
const config = require("../config/auth.config");
|
||||
const User = db.user;
|
||||
const Role = db.role;
|
||||
const { user: User, role: Role, refreshToken: RefreshToken } = db;
|
||||
|
||||
const Op = db.Sequelize.Op;
|
||||
|
||||
|
|
@ -47,16 +46,12 @@ exports.signin = (req, res) => {
|
|||
email: req.body.email
|
||||
}
|
||||
})
|
||||
.then(user => {
|
||||
.then(async (user) => {
|
||||
if (!user) {
|
||||
return res.status(404).send({ message: "User Not found." });
|
||||
}
|
||||
|
||||
const passwordIsValid = user.validPassword(req.body.password);
|
||||
// const passwordIsValid = bcrypt.compareSync(
|
||||
// req.body.password,
|
||||
// user.password
|
||||
// );
|
||||
|
||||
if (!passwordIsValid) {
|
||||
return res.status(401).send({
|
||||
|
|
@ -70,9 +65,11 @@ exports.signin = (req, res) => {
|
|||
{
|
||||
algorithm: 'HS256',
|
||||
allowInsecureKeySizes: true,
|
||||
expiresIn: 86400, // 24 hours
|
||||
expiresIn: config.jwtExpiration
|
||||
});
|
||||
|
||||
let refreshToken = await RefreshToken.createToken(user);
|
||||
|
||||
const authorities = [];
|
||||
user.getRoles().then(roles => {
|
||||
for (let i = 0; i < roles.length; i++) {
|
||||
|
|
@ -83,7 +80,8 @@ exports.signin = (req, res) => {
|
|||
username: user.username,
|
||||
email: user.email,
|
||||
roles: authorities,
|
||||
accessToken: token
|
||||
accessToken: token,
|
||||
refreshToken: refreshToken
|
||||
});
|
||||
});
|
||||
})
|
||||
|
|
@ -91,3 +89,43 @@ exports.signin = (req, res) => {
|
|||
res.status(500).send({ message: err.message });
|
||||
});
|
||||
};
|
||||
|
||||
exports.refreshToken = async (req, res) => {
|
||||
const { refreshToken: requestToken } = req.body;
|
||||
|
||||
if (requestToken == null) {
|
||||
return res.status(403).json({ message: "Refresh Token is required!" });
|
||||
}
|
||||
|
||||
try {
|
||||
let refreshToken = await RefreshToken.findOne({ where: { token: requestToken } });
|
||||
|
||||
console.log(refreshToken)
|
||||
|
||||
if (!refreshToken) {
|
||||
res.status(403).json({ message: "Refresh token is not in database!" });
|
||||
return;
|
||||
}
|
||||
|
||||
if (RefreshToken.verifyExpiration(refreshToken)) {
|
||||
RefreshToken.destroy({ where: { id: refreshToken.id } });
|
||||
|
||||
res.status(403).json({
|
||||
message: "Refresh token was expired. Please make a new signin request",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const user = await refreshToken.getUser();
|
||||
let newAccessToken = jwt.sign({ id: user.id }, config.secret, {
|
||||
expiresIn: config.jwtExpiration,
|
||||
});
|
||||
|
||||
return res.status(200).json({
|
||||
accessToken: newAccessToken,
|
||||
refreshToken: refreshToken.token,
|
||||
});
|
||||
} catch (err) {
|
||||
return res.status(500).send({ message: err });
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,29 +3,33 @@ const config = require("../config/auth.config.js");
|
|||
const db = require("../models");
|
||||
const User = db.user;
|
||||
|
||||
verifyToken = (req, res, next) => {
|
||||
const { TokenExpiredError } = jwt;
|
||||
|
||||
const catchError = (err, res) => {
|
||||
if (err instanceof TokenExpiredError) {
|
||||
return res.status(401).send({ message: "Unauthorized! Access Token was expired!" });
|
||||
}
|
||||
|
||||
return res.sendStatus(401).send({ message: "Unauthorized!" });
|
||||
}
|
||||
|
||||
const verifyToken = (req, res, next) => {
|
||||
let token = req.headers["x-access-token"];
|
||||
|
||||
if (!token) {
|
||||
return res.status(403).send({
|
||||
message: "No token provided!"
|
||||
});
|
||||
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();
|
||||
});
|
||||
jwt.verify(token, config.secret, (err, decoded) => {
|
||||
if (err) {
|
||||
return catchError(err, res);
|
||||
}
|
||||
req.userId = decoded.id;
|
||||
next();
|
||||
});
|
||||
};
|
||||
|
||||
isAdmin = (req, res, next) => {
|
||||
const isAdmin = (req, res, next) => {
|
||||
User.findByPk(req.userId).then(user => {
|
||||
user.getRoles().then(roles => {
|
||||
for (let i = 0; i < roles.length; i++) {
|
||||
|
|
@ -42,7 +46,7 @@ isAdmin = (req, res, next) => {
|
|||
});
|
||||
};
|
||||
|
||||
isModerator = (req, res, next) => {
|
||||
const isModerator = (req, res, next) => {
|
||||
User.findByPk(req.userId).then(user => {
|
||||
user.getRoles().then(roles => {
|
||||
for (let i = 0; i < roles.length; i++) {
|
||||
|
|
@ -59,7 +63,7 @@ isModerator = (req, res, next) => {
|
|||
});
|
||||
};
|
||||
|
||||
isModeratorOrAdmin = (req, res, next) => {
|
||||
const isModeratorOrAdmin = (req, res, next) => {
|
||||
User.findByPk(req.userId).then(user => {
|
||||
user.getRoles().then(roles => {
|
||||
for (let i = 0; i < roles.length; i++) {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ db.role = require("../models/role.model.js")(sequelize);
|
|||
db.pitchType = require("../models/pitchType.model.js")(sequelize);
|
||||
db.pitch = require("../models/pitch.model.js")(sequelize);
|
||||
db.bullpenSession = require("../models/bullpenSession.model.js")(sequelize);
|
||||
db.refreshToken = require("../models/refreshToken.model.js")(sequelize);
|
||||
|
||||
db.role.belongsToMany(db.user, {
|
||||
through: "UserRoles"
|
||||
|
|
@ -41,6 +42,12 @@ db.role.belongsToMany(db.user, {
|
|||
db.user.belongsToMany(db.role, {
|
||||
through: "UserRoles"
|
||||
});
|
||||
db.refreshToken.belongsTo(db.user, {
|
||||
foreignKey: 'userId', targetKey: 'id'
|
||||
});
|
||||
db.user.hasOne(db.refreshToken, {
|
||||
foreignKey: 'userId', targetKey: 'id'
|
||||
});
|
||||
|
||||
db.ROLES = ["user", "admin", "moderator"];
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
const { DataTypes } = require('sequelize');
|
||||
const config = require("../config/auth.config");
|
||||
const { v4: uuidv4 } = require("uuid");
|
||||
|
||||
module.exports = (sequelize, Sequelize) => {
|
||||
const RefreshToken = sequelize.define("refreshToken", {
|
||||
token: {
|
||||
type: DataTypes.STRING,
|
||||
},
|
||||
expiryDate: {
|
||||
type: DataTypes.DATE,
|
||||
},
|
||||
});
|
||||
|
||||
RefreshToken.createToken = async function (user) {
|
||||
let expiredAt = new Date();
|
||||
|
||||
expiredAt.setSeconds(expiredAt.getSeconds() + config.jwtRefreshExpiration);
|
||||
|
||||
let _token = uuidv4();
|
||||
|
||||
let refreshToken = await this.create({
|
||||
token: _token,
|
||||
userId: user.id,
|
||||
expiryDate: expiredAt.getTime(),
|
||||
});
|
||||
|
||||
return refreshToken.token;
|
||||
};
|
||||
|
||||
RefreshToken.verifyExpiration = (token) => {
|
||||
return token.expiryDate.getTime() < new Date().getTime();
|
||||
};
|
||||
|
||||
return RefreshToken;
|
||||
};
|
||||
|
|
@ -18,7 +18,8 @@
|
|||
"pg": "^8.13.3",
|
||||
"pg-hstore": "^2.3.4",
|
||||
"sequelize": "^6.37.5",
|
||||
"sqlite3": "^5.1.7"
|
||||
"sqlite3": "^5.1.7",
|
||||
"uuid": "^11.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"sequelize-cli": "^6.6.2"
|
||||
|
|
@ -3258,6 +3259,15 @@
|
|||
"node": ">= 10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sequelize/node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/serve-static": {
|
||||
"version": "1.16.2",
|
||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
|
||||
|
|
@ -3891,12 +3901,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz",
|
||||
"integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
"uuid": "dist/esm/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/validator": {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,8 @@
|
|||
"pg": "^8.13.3",
|
||||
"pg-hstore": "^2.3.4",
|
||||
"sequelize": "^6.37.5",
|
||||
"sqlite3": "^5.1.7"
|
||||
"sqlite3": "^5.1.7",
|
||||
"uuid": "^11.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"sequelize-cli": "^6.6.2"
|
||||
|
|
|
|||
|
|
@ -20,4 +20,5 @@ module.exports = function(app) {
|
|||
);
|
||||
|
||||
app.post("/api/auth/signin", controller.signin);
|
||||
app.post("/api/auth/refreshtoken", controller.refreshToken);
|
||||
};
|
||||
Loading…
Reference in New Issue