v0.0.8 Security and logout - zhentian-wan/MEANAppsFiles GitHub Wiki

We need to crypt the user password CANNOT leave it as text.

**Install: **

 npm install crypto --save

Crypt the password

We pass password and a random salt to a hash algorithm, then it will generate the Hashed password. This hashed password cannot be reversed to the text password. So it has a high security.

config/mongoose.js

crypto = require('crypto');

    //Users data
    var userSchema = mongoose.Schema({
        firstName: String,
        lastName: String,
        username: String,
        salt: String,
        hash_pwd: String
    });

    //Add a method to the userSchema, which authenticate the user.
    userSchema.methods = {
        authenticate: function(passwordToMatch){
            return hashPwd(this.salt, passwordToMatch) === this.hash_pwd;
        }
    };

We need to update the user schema, add salt and hash_pwd.

We also need methods to generate salt and hash_pwd

function createSalt(){
    return crypto.randomBytes(128).toString('base64');
}

function hashPwd(salt, pwd){
    var hmac = crypto.createHmac('sha1', salt);
    return hmac.update(pwd).digest('hex');
}

Test Data

    User.find({}).exec(function(err, collection){
        if(_.size(collection) === 0){
            var salt, hash;
            salt = createSalt();
            hash = hashPwd(salt, 'John');
            User.create({firstName: 'John', lastName: 'Linquist', username: 'John', salt: salt, hash_pwd: hash});
            salt = createSalt();
            hash = hashPwd(salt, 'Ken');
            User.create({firstName: 'Ken', lastName: 'CD', username: 'Ken', salt: salt, hash_pwd: hash});
            salt = createSalt();
            hash = hashPwd(salt, 'Ben');
            User.create({firstName: 'Ben', lastName: 'Cophen', username: 'Ben', salt: salt, hash_pwd: hash});
        }
    })

We just use username as password to create test data.

config/passport.js So when we authenticate the user, not only check the username exists or not, we also check the password.

    passport.use(new LocalStrategy(
        function(username, password, done){
            User.findOne({username: username}).exec(function(err, user){

                if(user && user.authenticate(password)){
                    return done(null, user);
                }else{
                    return done(null, false);
                }
            });
        }
    ));

Once page refreshed, client side need to login again problem

To fix this problem, first we need to know that once the user has logged in, the server side know the logged in user. Even user refresh the page. But client side doesn't know, because we didn't save the information.

So on the server side, when we send back index page, we also send back the current user if any. And on the client side once user logged in, we save the user information in $window. so when the page refreshed, if the $window info exists, we show the logged in status.

server side

config/routes.js

    // All routes handled by this route, give client side to handle
    app.get('*', function(req,res) {
        res.render('index', {
            bootstrappedUser: req.user  //server will remember the current user
        });
    });
client side

layout.jade Include a new file called currentUser

doctype
html
    head
        title Multivision
        link(href="/favicon.ico", rel="shortcut icon", type="image/x-icon")
        link(href="/css/bootstrap.css", rel="stylesheet")
        link(href="/vendor/toastr/toastr.min.css" rel='stylesheet')
        link(href="/css/site.css", rel="stylesheet")

    body(ng-app="app")
        include currentUser
        block main-content
        //include all the javascript files
        include scripts

currentUser.jade: Add bootstrappedUser to the window object using json format

if !!bootstrappedUser
   script
      window.bootstrappedUserObject = !{JSON.stringify(bootstrappedUser)}

identiy.js

Check whether bootstrappedUserObject exists.

function IdentityFactory($window) {

    var factory = {},
        currentUser;

    if($window.bootstrappedUserObject ){
        currentUser = $window.bootstrappedUserObject;
    }

    factory.currentUser = currentUser;
    factory.isAuthed = function() {
        return  !!factory.currentUser;
    };

    return factory;
}

angular.module('app')

    .factory('IdentityFactory', IdentityFactory);