└── README.md /README.md: -------------------------------------------------------------------------------- 1 | # Quick Cheatsheet for Adding Passport.js to a Sails.js version 1.0 Application 2 | cheatsheet version 1.3 3 | 4 | ## Pre Actions 5 | Creating a new sails application 6 | ### 1. Install new app. 7 | ``` 8 | sails new appname 9 | ``` 10 | ### 2. Change directory into the app 11 | ``` 12 | cd appname 13 | ``` 14 | 15 | ## 1. install the npm packages 16 | ``` 17 | npm install passport 18 | npm install passport-local 19 | npm install bcrypt-nodejs 20 | ``` 21 | 22 | ## 2. MiddleWare Ordering 23 | Add the following to the middleware for the passport application in "config/http.js", 24 | ### 2.1 Step 1 25 | First uncomment the order 26 | ### 2.2 Step 2 27 | Insert "passportInit" and "passportSession" below "session". 28 | ``` 29 | order: [ 30 | 'cookieParser', 31 | 'session', 32 | 'passportInit', // <==== If you're using "passport", you'll want to have its two 33 | 'passportSession', // <==== middleware functions run after "session". 34 | 'bodyParser', 35 | 'compress', 36 | 'poweredBy', 37 | 'router', 38 | 'www', 39 | 'favicon', 40 | ], 41 | ``` 42 | 43 | ## 3. Middleware Initialisers 44 | Next, Add middleware initialisers for passport and passport-local to "config/http.js" 45 | ``` 46 | /*************************************************************************** 47 | * * 48 | * Initialise for both passport and passport-local * 49 | * * 50 | * https://sailsjs.com/config/http#?customizing-the-body-parser * 51 | * * 52 | ***************************************************************************/ 53 | 54 | passportInit : (function (){ 55 | return require('passport').initialize(); 56 | })(), 57 | 58 | passportSession : (function (){ 59 | return require('passport').session(); 60 | })() 61 | ``` 62 | 63 | 64 | ## 4. User Model 65 | Create a new user model with the command and template 66 | ### 4.1 Step 1 67 | Use the following command to create the model 68 | ``` 69 | sails generate model user 70 | ``` 71 | 72 | ### 4.2 Step 2 73 | Add the following to the newly created user model. 74 | ``` 75 | const bcrypt = require('bcrypt-nodejs'); 76 | module.exports = { 77 | attributes: { 78 | username: { 79 | type: 'string', 80 | required: true 81 | }, 82 | email: { 83 | type: 'string', 84 | required: true 85 | }, 86 | password: { 87 | type: 'string', 88 | required: true 89 | } 90 | }, 91 | customToJSON: function() { 92 | return _.omit(this, ['password']) 93 | }, 94 | beforeCreate: function(user, cb){ 95 | bcrypt.genSalt(10, function(err, salt){ 96 | bcrypt.hash(user.password, salt, null, function(err, hash){ 97 | if(err) return cb(err); 98 | user.password = hash; 99 | return cb(); 100 | }); 101 | }); 102 | } 103 | }; 104 | ``` 105 | 106 | ## 5. Auth Controller 107 | Create a new auth controller with the command and template 108 | ### 5.1 Step 1 109 | Use the following command to create the controller 110 | ``` 111 | sails generate controller auth 112 | ``` 113 | 114 | ### 5.2 Step 2 115 | Add the following to the Auth controller 116 | ``` 117 | /** 118 | * AuthController 119 | * 120 | * @description :: Server-side actions for handling incoming requests. 121 | * @help :: See https://sailsjs.com/docs/concepts/actions 122 | */ 123 | const passport = require('passport'); 124 | module.exports = { 125 | //Login function 126 | login: function(req, res) { 127 | passport.authenticate('local', function(err, user, info){ 128 | if((err) || (!user)) return res.send({ message: info.message, user}); 129 | 130 | req.login(user, function(err) { 131 | if(err) res.send(err); 132 | return res.redirect('/'); 133 | }); 134 | })(req, res); 135 | }, 136 | //Logout function 137 | logout: function(req, res) { 138 | req.logout(); 139 | res.redirect('/'); 140 | }, 141 | //Register function 142 | register: function(req, res){ 143 | //TODO: form validation here 144 | data = { 145 | username: req.body.username, 146 | email: req.body.email, 147 | password: req.body.password, 148 | description: req.body.description 149 | } 150 | User.create(data).fetch().exec(function(err, user){ 151 | if (err) return res.negoiate(err); 152 | 153 | //TODO: Maybe send confirmation email to the user before login 154 | req.login(user, function(err){ 155 | if (err) return res.negotiate(err); 156 | sails.log('User '+ user.id +' has logged in.'); 157 | return res.redirect('/'); 158 | }) 159 | }) 160 | } 161 | }; 162 | ``` 163 | 164 | ## 6. Create config/Passport.js 165 | Create a new file in the config folder named 'passport.js', Load passport via require and bcrypt for password hashing. 166 | ``` 167 | const passport = require('passport'), 168 | LocalStrategy = require('passport-local').Strategy, 169 | bcrypt = require('bcrypt-nodejs'); 170 | passport.serializeUser(function(user, cb) { 171 | cb(null, user.id); 172 | }); 173 | passport.deserializeUser(function(id, cb){ 174 | User.findOne({id}, function(err, user) { 175 | cb(err, user); 176 | }); 177 | }); 178 | passport.use(new LocalStrategy({ 179 | usernameField: 'username', 180 | passportField: 'password' 181 | }, function(username, password, cb){ 182 | User.findOne({username: username}, function(err, user){ 183 | if(err) return cb(err); 184 | if(!user) return cb(null, false, {message: 'Username not found'}); 185 | bcrypt.compare(password, user.password, function(err, res){ 186 | if(!res) return cb(null, false, { message: 'Invalid Password' }); 187 | return cb(null, user, { message: 'Login Succesful'}); 188 | }); 189 | }); 190 | })); 191 | ``` 192 | 193 | ## 7. Add Policies 194 | Add the following policies "config/policies.js" which will block all controllers except the Auth controller from access before signing in. 195 | ``` 196 | /*************************************************************************** 197 | * * 198 | * Default policy for all controllers and actions, unless overridden. * 199 | * (`true` allows public access) * 200 | * * 201 | ***************************************************************************/ 202 | 203 | '*': 'authenticated', 204 | // whitelist the auth controller 205 | 'auth': { 206 | '*': true 207 | } 208 | ``` 209 | ## 8. Create api/policies/ 210 | Create a new file in the "api/policies/" folder called "authenticated.js" 211 | Past in the below code which handles checking if the current user is login and allowed to continue to view the hidden pages. 212 | ``` 213 | // We use passport to determine if we're authenticated 214 | module.exports = function(req, res, next) { 215 | 216 | 'use strict'; 217 | 218 | // Sockets 219 | if(req.isSocket) 220 | { 221 | if(req.session && 222 | req.session.passport && 223 | req.session.passport.user) 224 | { 225 | return next(); 226 | } 227 | 228 | res.json(401); 229 | } 230 | // HTTP 231 | else 232 | { 233 | if(req.isAuthenticated()) 234 | { 235 | return next(); 236 | } 237 | 238 | // If you are using a traditional, server-generated UI then uncomment out this code: 239 | res.redirect('/explore'); 240 | 241 | 242 | // If you are using a single-page client-side architecture and will login via socket or Ajax, then uncomment out this code: 243 | /* 244 | res.status(401); 245 | res.end(); 246 | */ 247 | } 248 | 249 | }; 250 | ``` 251 | 252 | ## 9. Database Connection 253 | Add the mongodb url and adapter to the default settings page "config/datastores.js" 254 | ``` 255 | adapter: 'sails-mongo', 256 | url: 'mongodb://localhost:27017/passportexample', 257 | ``` 258 | 259 | ## 10. Update config/models.js 260 | Update the models config file "config/models.js" with the different id field when using mongodb. 261 | ``` 262 | attributes: { 263 | createdAt: { type: 'number', autoCreatedAt: true, }, 264 | updatedAt: { type: 'number', autoUpdatedAt: true, }, 265 | id: { type: 'string', columnName: '_id' }, 266 | //-------------------------------------------------------------------------- 267 | // /\ Using MongoDB? 268 | // || Replace `id` above with this instead: 269 | // 270 | // ``` 271 | // id: { type: 'string', columnName: '_id' }, 272 | // ``` 273 | //-------------------------------------------------------------------------- 274 | }, 275 | ``` 276 | 277 | ## 11. Add Routes 278 | Make sure to add your urls to the routes page "config/routes.js" 279 | ``` 280 | //Auth 281 | 'get /login': { 282 | view: 'user/login' 283 | }, 284 | 'get /register': { 285 | view: 'user/register' 286 | }, 287 | 'post /login': 'AuthController.login', 288 | 'post /register': 'AuthController.register', 289 | '/logout': 'AuthController.logout', 290 | ``` 291 | 292 | ## 12. Register & Login Froms 293 | The HTML forms representing the Register page and Login Page. 294 | ### 12.1 Register Page 295 | ``` 296 |