Reputation: 51
I'm trying to add a role called admin to authenticate admins logged into dashboard web app while the normal user can just access the regular pages.
For a normal user, I require the passport in server.js
like
// use passport
app.use(passport.initialize());
require("./config/passport")(passport);
In the config/passport.js
, like the code in official example, I try this:
const JwtStrategy = require('passport-jwt').Strategy,
ExtractJwt = require('passport-jwt').ExtractJwt;
const mongoose = require('mongoose');
const User = mongoose.model("users");
const key =require("../config/key");
const opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = key.secretKey;
module.exports = passport => {
passport.use(new JwtStrategy(opts, (jwt_payload, done) => {
// console.log(jwt_payload);
User.findById(jwt_payload.id)
.then(user => {
if(user) {
return done(null, user);
}
return done(null, false);
})
.catch(err => console.log(err));
}));
};
This way works fine, and I use them in the route
router.get("/current", passport.authenticate("jwt", {session: false}), (req, res) => {
res.json({
id: req.user.id,
name: req.user.name,
username: req.user.username,
email: req.user.email,
avatar: req.user.avatar,
});
})
However, while I'm adding a role in the token rule:
const rule = {id:admin.id, email: admin.email, avatar: admin.avatar, admin: admin.admin};
How could I check if the admin property is true to query different Collections in passport.js
I tried this, which doesn't work for me with the error seems like the server run twice:
module.exports = passport => {
passport.use(new JwtStrategy(opts, (jwt_payload, done) => {
// console.log(jwt_payload);
if(jwt_payload.admin){
Admin.findById(jwt_payload.id)
.then(user => {
if(user) {
return done(null, user);
}
return done(null, false);
})
.catch(err => console.log(err));
} else {
User.findById(jwt_payload.id)
.then(user => {
if(user) {
return done(null, user);
}
return done(null, false);
})
.catch(err => console.log(err));
}
}));};
The error is : Error
Upvotes: 1
Views: 2730
Reputation: 4011
Here is what I do and it works pretty well... I simply include the isAdmin: Boolean
in my user model like so:
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
minlength: 5,
maxlength: 50
},
email: {
type: String,
required: true,
minlength: 5,
maxlength: 255,
unique: true
},
password: {
type: String,
required: true,
minlength: 5,
maxlength: 1024
},
isAdmin: Boolean
});
and then include this in the jwt like so:
userSchema.methods.generateAuthToken = function() {
const token = jwt.sign({ _id: this._id, isAdmin: this.isAdmin }, config.get('jwtPrivateKey'));
return token;
}
then a custom middleware to check the value of isAdmin like so:
module.exports = function (req, res, next) {
if (!req.user.isAdmin) return res.status(403).send('Access denied.');
next();
}
then I simply import it and use it as the second param for any route like so:
router.patch('/:id', [auth, isAdmin, validateObjectId], async (req, res) => {
// handle the route (in order to do anything in this route you would need be an admin...)
});
EDIT: If you're curious about the other two middleware here they are...
auth.js:
const jwt = require('jsonwebtoken');
const config = require('config');
module.exports = function (req, res, next) {
const token = req.header('x-auth-token');
if (!token) return res.status(401).send('Access denied. No token provided.');
try {
const decoded = jwt.verify(token, config.get('jwtPrivateKey'));
req.user = decoded;
next();
}
catch (ex) {
res.status(400).send('Invalid token.');
}
}
validateObjectId:
const mongoose = require('mongoose');
module.exports = function(req, res, next) {
if (!mongoose.Types.ObjectId.isValid(req.params.id))
return res.status(404).send('Invalid ID.');
next();
}
Upvotes: 3