Authenticated Routes - protecting resources

In this section we will be covering how to protect resources.

The first thing we need to do is create a way to establish roles for our user. Lets create a test.

Add the roles attribute to the user model

  1. Create user roles tests:

    test/users/models.js

     //... imports
    
     describe('Users: models', function () {
    
       //... previous tests
    
       describe('#hasRole', function () {
         // we will set this value in the beforeEach function
         var user;
    
         // beforeEach test create a user
         beforeEach(function (done) {
           var u = {
             roles: ['admin', 'mod']
           };
           User.create(u, function (err, createdUser) {
             user = createdUser;
             done();
           });
         });
         it('should return true if the user has role', function (done) {
           user.hasRole('admin').should.be.true;
           user.hasRole('mod').should.be.true;
           done();
         });
         it('should return false if the user does not have role', function (done) {
           user.hasRole('astronaut').should.be.false;
           user.hasRole('cowboy').should.be.false;
           done();
         });
       });
     });
    

    Tests will fail:

     2) Users: models #hasRole should return false if the user does not have role:
      TypeError: Object { __v: 0, _id: 507b2b20f74953000000000a, emails: [] } has no method 'hasRole'
    
  2. Write the code:

    users/modles.js

     //... previous code
    
     var userSchema = new Schema({
       //... previous attributes
    
       roles: Array
     });
    
     //... previous static methods
    
     userSchema.methods.hasRole = function (role) {
       for (var i = 0; i < this.roles.length; i++) {
         if (this.roles[i] === role) {
           // if the role that we are checking matches the 'role' we are
           // looking for return true
           return true;
         }
    
       };
       // if the role does not match return false
       return false;
     };
    

    We are using mongoose methods to add a hasRole method to our user schema.

    Our tests are now passing.

     ✔ 13 tests complete (235 ms)
    

Create a middleware to confirm that the the user is authenticated

  1. Create the test:

    test/auth/middlewares.js

    TODO: there was a problem when calling supertest multiple times. I.e. first logging in a user, then checking credentials. This test will have to wait until after this test is resolved.

    Tests are now failing:

     1) Passport: middleware user not logged in should redirect to "/login":
      AssertionError: expected [Error: expected 302 "Moved Temporarily", got 404 "Not Found"] to not exist
    
  2. Add the route:

    app.js

     //...
     var admin = require('./routes/admin');
    
     //...
    
     app.get('/admin', admin.index);
    
     //...
    

    /routes/admin.js

     'use strict';
    
     // GET admin index.
    
     exports.index = function (req, res) {
       res.send("welcome to the admin");
     };
    

    The test is now failing with:

     1) Passport: middleware user not logged in should redirect to "/login":
       AssertionError: expected [Error: expected 302 "Moved Temporarily", got 200 "OK"] to not exist
    
  3. Create the ensureAuthenticated and ensureAdmin middleware:

    auth/middlewares.js

     'use strict';
    
     // Simple route middleware to ensure user is authenticated.
     //   Use this route middleware on any resource that needs to be protected.  If
     //   the request is authenticated (typically via a persistent login session),
     //   the request will proceed.  Otherwise, the user will be redirected to the
     //   login page.
     exports.ensureAuthenticated =  function (req, res, next) {
       if (req.isAuthenticated()) {
         return next();
       }
       return res.redirect('/login');
     };
    
     exports.ensureAdmin =  function (req, res, next) {
       // make sure the user is logged in.
       if (req.isAuthenticated()) {
         // make sure the user has role 'admin'
         if (req.user.hasRole('admin')) {
           return next();
         }
       }
       // otherwise redirect to login
       return res.redirect('/login');
     };
    

    For more info on express middleware

  4. Add the ensureAdmin middleware to our '/auth' routes:

    app.js

     //... imports
    
     var ensureAuthenticated = require('./auth/middlewares').ensureAuthenticated;
    
     //... routes
    
     app.get('/admin', ensureAdmin, admin.index);
    

    Tests are now passing:

     ✔ 17 tests complete (645 ms)
    

Resources:

Comments