David Karlsson
David Karlsson

Reputation: 9716

MEAN js require authorization to list items

In my mean js app i have an account model and corresponding routes and controllers. To remove a specific account i need to have authorization and I need to be logged in.

All users can however list all accounts, I only wont to list the accounts created by the specific user. So i need to add autorization to the list part of the code.

I update the routes for app.route('/accounts') with users.requiresLoginandaccounts.hasAuthorization as shown below:

module.exports = function(app) {
    var users = require('../../app/controllers/users.server.controller');
    var accounts = require('../../app/controllers/accounts.server.controller');

    // Accounts Routes
    app.route('/accounts')
        .get(users.requiresLogin,accounts.hasAuthorization,accounts.list)
        .post(users.requiresLogin, accounts.create);

    app.route('/accounts/:accountId')
        .get(users.requiresLogin, accounts.hasAuthorization,accounts.read)
        .put(users.requiresLogin, accounts.hasAuthorization, accounts.update)
        .delete(users.requiresLogin, accounts.hasAuthorization, accounts.delete);

    // Finish by binding the Account middleware
    app.param('accountId', accounts.accountByID);
};

Now I get an errror since req is not provided with user.

GET /modules/accounts/views/list-accounts.client.view.html 304 8.266 ms - - TypeError: Cannot read property 'user' of undefined at exports.hasAuthorization (/Users/david/Repositories/budget/app/controllers/accounts.server.controller.js:103:17)

So I imagine i need to update the accounts.server.controller somehow. The delete account does provide an account in the req, so that only the creator can delete as I mentioned earlier. How do I update the code so that the "List of accounts" part work and list only the accounts belonging to that specific user?

/**
 * Delete an Account
 */
exports.delete = function(req, res) {
    var account = req.account ;

    account.remove(function(err) {
        if (err) {
            return res.status(400).send({
                message: errorHandler.getErrorMessage(err)
            });
        } else {
            res.jsonp(account);
        }
    });
};

/**
 * List of Accounts
 */
exports.list = function(req, res) {
    Account.find().sort('-created').populate('user', 'displayName').exec(function(err, accounts) {
        if (err) {
            return res.status(400).send({
                message: errorHandler.getErrorMessage(err)
            });
        } else {
            res.jsonp(accounts);
        }
    });
};

/**
 * Account middleware
 */
exports.accountByID = function(req, res, next, id) { 
    Account.findById(id).populate('user', 'displayName').exec(function(err, account) {
        if (err) return next(err);
        if (! account) return next(new Error('Failed to load Account ' + id));
        req.account = account ;
        next();
    });
};

/**
 * Account authorization middleware
 */
exports.hasAuthorization = function(req, res, next) {
    if (req.account.user.id !== req.user.id) {
        return res.status(403).send('User is not authorized');
    }
    next();
};

The account client service only contains the basic stuff:

//Accounts service used to communicate Accounts REST endpoints
angular.module('accounts').factory('Accounts', ['$resource',
    function($resource) {
        return $resource('accounts/:accountId', { accountId: '@_id'
        }, {
            update: {
                method: 'PUT'
            }
        });
    }
]);

And the user object is not mentioned in the controller.

Upvotes: 0

Views: 772

Answers (1)

teleaziz
teleaziz

Reputation: 2240

The accounts.hasAuthorization assume it get executed after the accounts.accountById ,on your current configuration req.account will be undefined.

I'm assumming that somewhere in your account model you have:

user: {
    type: Schema.ObjectId,
    ref: 'User'
}

If you want the user only have access only to the accounts he/she owns :

  • Change accounts.list route only to requires Login and this gives us access to the req.user :

    app.route('/accounts')
             .get(users.requiresLogin,accounts.list)
    
  • Change the exports.list in the accounts controller:

    exports.list = function(req, res) {
        Account.find({user: req.user._id}).sort('-created')
    .... //
    
    };
    

Upvotes: 1

Related Questions