Not sure of a clean way to go about his. Let's say I have this endpoint:
GET /api/Books/
For the user on the webservice, this will return only the user's resources. It might look a little something like this:
exports.getBooks = function(req, res) {
// find all books for user
BookModel.find({ userId: req.user._id }, function(err, books) {
if (err)
res.send(err);
res.json(books);
});
};
The web service using the api needs the user to be logged in first. I can achieve this using a basic passport strategy to ensure authentication. But let's say I have an admin account that needs to see ALL books ever recorded. What's more is that the admin account and user accounts have completely different properties so assigning a Boolean
for permissions is not enough. Using the same endpoint:
GET /api/Books
I see no reason to write another endpoint to achieve this. However the difference would look like this:
exports.getBooks = function(req, res) {
// find all books in the database
BookModel.find({}, function(err, books) {
if (err)
res.send(err);
res.json(books);
});
};
However I cannot come up with a clean way to achieve this while also using the passport middlewear as it is intended like so:
router.route('/books')
.post(authController.isAuthenticated, bookController.postBooks)
.get(authController.isAuthenticated, bookController.getBooks);
The function isAuthenticated
will will only verify whether or not the user requesting resources has permission and does not change the way the controller behaves. I'm open to ideas.
ANSWER
The user @ZeroCho suggested to check user properties in req.user
object to determine what should be sent back. This was more simple than I expected. In my implementation for passport.BasicAuth
strategy, I check which table has a matching doc. Once the user is found in the common user or Admin user table all you do is add a property in the isMatch
return object.
// Basic strategy for users
passport.use('basic', new BasicStrategy(
function(email, password, done) {
verifyUserPassword(email, password,
function(err, isMatch) {
if(err) { return done(err); }
// Password did not match
if(!isMatch) { return done(null, false); }
// Success
var userInfo = {
email: email,
isAdmin: isMatch.isAdmin || false,
businessID: isMatch.businessID || false
};
return done(null, userInfo);
});
})
);
Then you can check if .isAdmin
or .businessID
is valid in your requests.
Just separate your controller by if statement
exports.getBooks = function(req, res) {
if (req.user.isAdmin) { // or some other code to check user is admin
// find all books in the database
BookModel.find({}, function(err, books) {
if (err)
res.send(err);
res.json(books);
});
} else {
BookModel.find({ userId: req.user._id }, function(err, books) {
if (err)
res.send(err);
res.json(books);
});
}
};