-
-
Save TyrfingMjolnir/5db92a46d6bac41d545a0251e1c079bb to your computer and use it in GitHub Desktop.
Node + Restify + Passport + Sessions + WebSockets
This file contains hidden or 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
| #!/usr/bin/env node | |
| const restify = require( 'restify' ); | |
| // Authentication | |
| const passport = require( 'passport' ); | |
| const LocalStrategy = require( 'passport-local' ).Strategy; | |
| const sessions = require( 'client-sessions' ); | |
| const server = restify.createServer(); | |
| server.use( restify.queryParser() ); | |
| server.use( restify.bodyParser() ); | |
| server.use( sessions({ | |
| // cookie name dictates the key name added to the request object | |
| cookieName: `session`, | |
| // should be a large unguessable string | |
| secret: `yoursecret`, | |
| // how long the session will stay valid in ms | |
| duration: 365 * 24 * 60 * 60 * 1000 | |
| })); | |
| // Initialize passport | |
| server.use( passport.initialize() ); | |
| // Set up the passport session | |
| server.use( passport.session() ); | |
| // This is how a user gets serialized | |
| passport.serializeUser( ( user, done ) => { | |
| done( null, user.id ); | |
| }); | |
| // This is how a user gets deserialized | |
| passport.deserializeUser( ( id, done ) => { | |
| // Look the user up in the database and return the user object | |
| // For this demo, return a static user | |
| return done( null, { | |
| id: 123456, | |
| username:`john` | |
| }); | |
| }); | |
| // Lookup a user in our database | |
| const lookupUser = ( username, password, done ) => { | |
| if( username === `john` && password === `johnspassword` ) { | |
| return done( null, { | |
| id: 123456, | |
| username: `john` } ); | |
| } | |
| return done( null, false, { | |
| error: `Incorrect username or password.` }); | |
| }; | |
| passport.use( new LocalStrategy( { | |
| usernameField: `username`, | |
| session: true | |
| }, lookupUser ) ); | |
| // POST /login | |
| const loginRoute = ( req, res, next ) => { | |
| // The local login strategy | |
| passport.authenticate( 'local', ( err, user ) => { | |
| if( err ) { | |
| return next( err ); | |
| } | |
| // Technically, the user should exist at this point, but if not, check | |
| if( ! user ) { | |
| return next( new restify.InvalidCredentialsError( `Please check your details and try again.` ) ); | |
| } | |
| // Log the user in! | |
| req.logIn( user, ( err ) => { | |
| if( err ) { | |
| return next( err ); | |
| } | |
| console.log( req.isAuthenticated() ); | |
| req.session.user_id = req.user.id; | |
| if( user.username ) { | |
| res.json( { success: `Welcome ${user.username}!`}); | |
| return next(); | |
| } | |
| res.json({ success: `Welcome!`}); | |
| return next(); | |
| }); | |
| })( req, res, next ); | |
| }; | |
| // GET /hello | |
| const helloRoute = ( req, res, next ) => { | |
| console.log( req.isAuthenticated() ); | |
| if( req.user ) { | |
| res.send( `Hello ${req.user.username}` ); | |
| } else { | |
| res.send( `Hello unauthenticated user` ); | |
| } | |
| return next(); | |
| }; | |
| server.post( { url: `/login` }, loginRoute ); | |
| server.get( { url: `/hello` }, helloRoute ); | |
| const io = require('socket.io').listen(server); | |
| /// Parse the given cookie header string into an object | |
| /// The object has the constious cookies as keys(names) => values | |
| /// @param {String} str | |
| /// @return {Object} | |
| const parseCookie = ( str, opt ) => { | |
| opt = opt || {}; | |
| const obj = {} | |
| const pairs = str.split(/[;,] */); | |
| const dec = opt.decode || decodeURIComponent; | |
| pairs.forEach( ( pair ) => { | |
| const eq_idx = pair.indexOf(`=`) | |
| // skip things that don't look like key=value | |
| if( eq_idx < 0 ) { | |
| return; | |
| } | |
| const key = pair.substr( 0, eq_idx ).trim() | |
| const val = pair.substr( ++eq_idx, pair.length ).trim(); | |
| // quoted values | |
| if( '"' == val[0] ) { | |
| val = val.slice( 1, -1 ); | |
| } | |
| // only assign once | |
| if( undefined == obj[key] ) { | |
| try { | |
| obj[key] = dec( val ); | |
| } catch( e ) { | |
| obj[key] = val; | |
| } | |
| } | |
| }); | |
| return obj; | |
| }; | |
| io.set( 'authorization', ( handshakeData, accept ) => { | |
| // Check that the cookie header is present | |
| if( ! handshakeData.headers.cookie ) { | |
| return accept( 'No cookie transmitted.', false ); | |
| } | |
| // Get all the cookie objects | |
| const cookie = parseCookie( handshakeData.headers.cookie ); | |
| // Pull out the user from the cookie by using the decode function | |
| handshakeData.sessionID = sessions.util.decode({ | |
| cookieName: 'session', | |
| secret:'yoursecret' | |
| }, | |
| cookie['session']); | |
| accept( null, true ); | |
| }); | |
| io.on( 'connection', ( socket ) => { | |
| // Get the first key of the handshake data | |
| const firstKey = Object.keys(socket.manager.handshaken)[0]; | |
| const userId = socket.manager.handshaken[firstKey].sessionID.content.user_id; | |
| // Send a hello message with the user's id | |
| socket.emit( `message`, `Hey ${userId}` ); | |
| }); | |
| // Launch the server | |
| server.listen( 5000, () => { | |
| console.log( `Server running at port 5000` ); | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment