Created
January 12, 2015 16:09
-
-
Save psi-4ward/70856147e30106cc8166 to your computer and use it in GitHub Desktop.
Sails.JS JWT Auth
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// policies/authenticated.js | |
module.exports = function(req, res, next) { | |
// adopt the User from the socket | |
if(req.isSocket && req.socket.User) { | |
req.User = req.socket.User; | |
return next(); | |
} | |
// get token from header an validate it | |
var token = req.headers["x-token"]; | |
function send401() { | |
res.send(401, {err: 'E_LOGIN_REQUIRED', message: 'Login required'}); | |
} | |
// validate we have all params | |
if(!token) return send401(); | |
// validate token and set req.User if we have a valid token | |
sails.services.tokenauth.verifyToken(token, function(err, data) { | |
if(err) return send401(); | |
sails.models.user.findOne({id: data.userId}, function(err, User) { | |
if(err) send401(); | |
req.User = User; | |
next(); | |
}); | |
}); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// controllers/LoginController.js | |
module.exports = { | |
index: function(req, res) { | |
var email = req.param('email'); | |
var password = req.param('password'); | |
// delay everthing to prevent bruteforce, dos and timing attacks | |
setTimeout(function() { | |
if(!email || !password) { | |
return res.json(401, {err: 'email and password required'}); | |
} | |
sails.models.user.findOne({email: email}, function(err, User) { | |
if(!User) { | |
return res.json(401, {err: 'invalid email or password'}); | |
} | |
User.verifyPassword(password, function(err, valid) { | |
if(err) { | |
return res.json(403, {err: 'forbidden'}); | |
} | |
if(!valid) { | |
return res.json(401, {err: 'invalid email or password'}); | |
} else { | |
res.json({user: User, token: sails.services.tokenauth.generateToken({userId: User.id})}); | |
// register in socket if this is a socket-request | |
if(req.isSocket) { | |
req.socket.User = User; | |
} | |
} | |
}); | |
}); | |
}, 200); | |
}, | |
/** | |
* attach the User to the socket using a token | |
* (socket.io reconnect) | |
* @param req | |
* @param res | |
* @returns {*} | |
*/ | |
authSocket: function(req, res) { | |
if(!req.isSocket) { | |
return res.json(400, 'This route is for socket connections only'); | |
} | |
var token = req.param('token'); | |
if(!token) return res.json(401, 'token missing'); | |
sails.services.tokenauth.getUser(token, function(err, User) { | |
if(err || !User) { | |
return res.json(401, 'token invalid'); | |
} | |
req.socket.User = User; | |
res.json(200, User.toJSON()); | |
}); | |
}, | |
/** | |
* "logout" for sockets | |
* @param req | |
* @param res | |
* @returns {*} | |
*/ | |
deauthSocket: function(req, res) { | |
if(!req.isSocket) { | |
return res.json(400, 'This route is for socket connections only'); | |
} | |
delete req.socket.User; | |
res.json(200, 'ok'); | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// services/tokenauth.js | |
var jwt = require('jsonwebtoken'); | |
var tokenauth = { | |
generateToken: function(payload) { | |
return jwt.sign(payload, sails.config.crypto.tokenSecret); | |
}, | |
verifyToken: function(token, cb) { | |
return jwt.verify(token, sails.config.crypto.tokenSecret, {}, cb); | |
}, | |
getUser: function(token, cb) { | |
tokenauth.verifyToken(token, function(err, data) { | |
if(err) return cb(err); | |
sails.models.user.findOne({id: data.userId}, function(err, User) { | |
if(err) return cb(err); | |
cb(null, User); | |
}); | |
}); | |
} | |
}; | |
module.exports = tokenauth; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// models/user.js | |
/** | |
* user.js | |
* @docs :: http://sailsjs.org/#!documentation/models | |
*/ | |
var bcrypt = require('bcrypt'); | |
module.exports = { | |
schema: false, | |
labels: { | |
name: { | |
title: "Name" | |
}, | |
email: { | |
title: "E-Mail" | |
}, | |
password: { | |
title: "Passwort" | |
}, | |
isAdmin: { | |
title: 'Administrator' | |
} | |
}, | |
types: { | |
password: function(password) { | |
return password === this.passwordConfirm; | |
} | |
}, | |
attributes: { | |
name: { | |
type: 'string' | |
}, | |
email: { | |
type: 'string', | |
required: true, | |
unique: true, | |
email: true, | |
minLength: 3 | |
}, | |
password: { | |
type: 'string', | |
password: true, | |
minLength: 8, | |
required: true | |
}, | |
isAdmin: { | |
type: 'boolean' | |
}, | |
// Alter JSON response | |
toJSON: function() { | |
var obj = this.toObject(); | |
delete obj.password; | |
return obj; | |
}, | |
verifyPassword: function(password, cb) { | |
return bcrypt.compare(password, this.password, cb); | |
} | |
}, | |
beforeCreate: function(data, cb) { | |
bcrypt.hash(data.password, sails.config.crypto.workFactor, function(err, hash) { | |
data.password = hash; | |
delete data.passwordConfirm; | |
cb(); | |
}); | |
}, | |
beforeUpdate: function(data, cb) { | |
if(data.password) { | |
bcrypt.hash(data.password, sails.config.crypto.workFactor, function(err, hash) { | |
data.password = hash; | |
delete data.passwordConfirm; | |
cb(); | |
}); | |
} else { | |
return cb(); | |
} | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment