Advertisement
Guest User

Untitled

a guest
May 24th, 2017
95
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.44 KB | None | 0 0
  1. # Express Auth Step-by-Step
  2.  
  3. ## Setup
  4.  
  5. Install the necessary dependencies.
  6. - `passport`
  7. - `passport-local`
  8. - `bcryptjs`
  9. - `cookie-parser`
  10. - `dotenv`
  11. - `express-session`
  12.  
  13. ## Create the User table.
  14.  
  15. In a new migration file in `db/migrations`:
  16.  
  17. ```sql
  18. # filename migration_[current-date].sql
  19. \connect [your_database_here]
  20.  
  21. CREATE TABLE IF NOT EXISTS users (
  22. id BIGSERIAL PRIMARY KEY,
  23. username VARCHAR(255) UNIQUE NOT NULL,
  24. first_name VARCHAR(255),
  25. last_name VARCHAR(255),
  26. email VARCHAR(255),
  27. password TEXT NOT NULL
  28. );
  29. ```
  30.  
  31. Then, run the migration: `psql -f migration_[date].sql`
  32.  
  33. ## Set up your `.env` style and add it to your `.gitignore`.
  34.  
  35. In the root directory of your app, create a file `.env`. **IMMEDIATELY ADD IT TO YOUR GITIGNORE BEFORE YOU MAKE ANY OTHER CHANGES!!!!!!!**
  36.  
  37. In `.env`, write this line:
  38.  
  39. ```
  40. SECRET_KEY=lsdjflskjdflkjsdflsdjfoiwerjlksdjflsd
  41. ```
  42.  
  43. ... except use a different secret key.
  44.  
  45. ```bash
  46. # You can generate a secret key using Python on the command line like so:
  47. $ python
  48. >>> import os
  49. >>> os.urandom(24)
  50. "\x02\xf3\xf7r\t\x9f\xee\xbbu\xb1\xe1\x90\xfe'\xab\xa6L6\xdd\x8d[\xccO\xfe"
  51. # put this in your .env!
  52. ```
  53.  
  54. ## Add the new dependencies to your `app.js`.
  55.  
  56. **Remember, don't copy and paste!!!!**
  57.  
  58. **STEP ONE**: Importing the new dependencies.
  59.  
  60. ```js
  61. // in app.js under requiring method override
  62. const session = require('express-session');
  63. const passport = require('passport');
  64.  
  65. // this will get our envorinment variables from the .env file
  66. require('dotenv').config();
  67. ```
  68.  
  69. **STEP TWO**: Setting the app up to use our new middlewares!
  70.  
  71. ```js
  72. // in app.js under `app.use(methodOverride('_method'))`
  73. app.use(session({
  74. secret: process.env.SECRET_KEY,
  75. resave: false,
  76. saveUninitialized: true,
  77. }));
  78. app.use(passport.initialize());
  79. app.use(passport.session());
  80. ```
  81.  
  82. ## Add the views for logging in and registering.
  83.  
  84. Refer to [these files](./views/auth) to see how these should look.
  85.  
  86. ## Create a User model.
  87.  
  88. **Step One**: In `models`, create a new file `user.js`.
  89.  
  90. It should look like this:
  91.  
  92. ```js
  93. const db = require('../db/config');
  94.  
  95. const User = {};
  96.  
  97. User.findByUserName = userName => {
  98. return db.oneOrNone('SELECT * FROM users WHERE username = $1', [userName]);
  99. };
  100.  
  101. User.create = user => {
  102. return db.one(
  103. `
  104. INSERT INTO users
  105. (username, first_name, last_name, email, password)
  106. VALUES ($1, $2, $3, $4, $5) RETURNING *
  107. `,
  108. [user.username, user.first_name, user.last_name, user.email, user.password]
  109. )
  110. };
  111.  
  112. module.exports = User;
  113. ```
  114.  
  115. ## Setting up Passport.
  116.  
  117. ### auth directory
  118.  
  119. Create a 'services' directory in the root of your app, and an `auth` directory inside that.
  120.  
  121. Add the following files to the auth directory: `auth-helpers.js`, `local.js`, and `passport.js`.
  122.  
  123. ### auth-helpers.js
  124.  
  125. This file will contain various helper functions that we use throughout our app. For now we are just going to add a function that will use bcrypt to compare passwords. Add the following code:
  126.  
  127. ```javascript
  128. const bcrypt = require('bcryptjs');
  129. const User = require('../../models/user');
  130.  
  131.  
  132. function comparePass(userPassword, databasePassword) {
  133. return bcrypt.compareSync(userPassword, databasePassword);
  134. }
  135. ```
  136.  
  137. ### passport.js
  138.  
  139. Add the following code:
  140.  
  141. ```javascript
  142. const passport = require('passport');
  143. const User = require('../../models/user');
  144.  
  145. module.exports = () => {
  146. passport.serializeUser((user, done) => {
  147. done(null, user.username);
  148. });
  149.  
  150. passport.deserializeUser((username, done) => {
  151. User.findByUserName(username)
  152. .then(user => {
  153. done(null, user);
  154. })
  155. .catch(err => {
  156. done(err, null);
  157. });
  158. });
  159. };
  160. ```
  161.  
  162. ### local.js
  163.  
  164. Add the following code:
  165.  
  166. ```javascript
  167. const passport = require('passport');
  168. const LocalStrategy = require('passport-local').Strategy;
  169.  
  170. const init = require('./passport');
  171. const User = require('../../models/user');
  172. const authHelpers = require('./auth-helpers');
  173.  
  174. const options = {};
  175.  
  176. init();
  177.  
  178. passport.use(
  179. new LocalStrategy(options, (username, password, done) => {
  180. User.findByUserName(username)
  181. .then(user => {
  182. if (!user) {
  183. return done(null, false);
  184. }
  185. if (!authHelpers.comparePass(password, user.password)) {
  186. return done(null, false);
  187. } else {
  188. return done(null, user);
  189. }
  190. })
  191. .catch(err => {
  192. console.log(err);
  193. return done(err);
  194. });
  195. })
  196. );
  197.  
  198. module.exports = passport;
  199. ```
  200.  
  201.  
  202.  
  203. ## Setting up our register, login, logout, & user routes
  204.  
  205. ### GET /auth/register
  206.  
  207. Now lets add the ability to register users. To do that we first need a registration form and a register route. In the routes directory, add `authRoutes.js`. Add the following code:
  208.  
  209. ```javascript
  210. const express = require('express');
  211. const authRouter = express.Router();
  212. const passport = require('../services/auth/local');
  213. const authHelpers = require('../services/auth/auth-helpers');
  214.  
  215.  
  216. authRouter.get('/login', authHelpers.loginRedirect, (req, res) => {
  217. res.render('auth/login');
  218. });
  219.  
  220. authRouter.get('/register', authHelpers.loginRedirect, (req, res) => {
  221. res.render('auth/register');
  222. });
  223. ```
  224.  
  225. Add this to `services/auth/authHelpers`:
  226.  
  227. ```javascript
  228. function loginRedirect(req, res, next) {
  229. if (req.user) res.redirect('/user');
  230.  
  231. return next();
  232. }
  233. ```
  234.  
  235.  
  236.  
  237. For now it will always `return next()`. Let's add our route to actually register the user!
  238.  
  239. ### POST /auth/register
  240.  
  241. When the user posts to the `/auth/register` route, the browser will send all the data contained in the form field to our express server. Our route middleware will then create a new user with that data. Add the following code to the `routes/authRoutes.js` file:
  242.  
  243. ```javascript
  244. authRouter.post('/register', (req, res, next) => {
  245. authHelpers.createNewUser(req, res)
  246. .then((user) => {
  247. req.login(user, (err) => {
  248. if (err) return next(err);
  249.  
  250. res.redirect('/user');
  251. });
  252. })
  253. .catch((err) => { res.status(500).json({ status: 'error' }); });
  254. });
  255. ```
  256.  
  257. The actual work of creating the user is offloaded to a function in our `auth-helpers` file. Let's add that code to that file:
  258.  
  259. ```js
  260. function createNewUser(req, res) {
  261. const salt = bcrypt.genSaltSync();
  262. const hash = bcrypt.hashSync(req.body.password, salt);
  263. return User.create({
  264. username: req.body.username,
  265. first_name: req.body.first_name,
  266. last_name: req.body.last_name,
  267. email: req.body.email,
  268. password: hash,
  269. });
  270. }
  271. ```
  272.  
  273. Now that we can register users, let's give them the ability to log in.
  274.  
  275. ### POST /auth/login
  276.  
  277. First we have to provide a page to log in. Add the following route to `routes/authRoutes`:
  278.  
  279. ```javascript
  280. authRouter.get('/login', authHelpers.loginRedirect, (req, res)=> {
  281. res.render('auth/login');
  282. });
  283. ```
  284.  
  285. Passport makes this POST route handler pretty easy to write. Add the following code to `routes/authRoutes`:
  286.  
  287. ```javascript
  288. authRouter.post('/login', passport.authenticate('local', {
  289. successRedirect: '/user',
  290. failureRedirect: '/auth/login',
  291. failureFlash: true
  292. })
  293. );
  294. ```
  295.  
  296. Passport authenticates the user for us based on the strategy we tell it to, in this case the local strategy. It authenticates according to the function in `auth/local.js`. Refer back to that to see what's going on there.
  297.  
  298. ### GET /logout
  299.  
  300. Logging out is pretty straightforward. Add the following, again, to `routes/authRoutes`:
  301.  
  302. ```javascript
  303. authRouter.get('/logout', (req, res) => {
  304. req.logout();
  305. res.redirect('/');
  306. });
  307.  
  308. module.exports = authRouter;
  309. ```
  310.  
  311. ### GET /user
  312.  
  313. Now that users can log in, we'll give them a user profile page. Let's add the following code to `routes/users`:
  314.  
  315. ```javascript
  316. const express = require('express');
  317. const userRoutes = express.Router();
  318. const authHelpers = require('../services/auth/auth-helpers');
  319.  
  320. /* GET users listing. */
  321.  
  322. userRoutes.get('/', authHelpers.loginRequired, (req, res) => {
  323. res.json({ user: 'user profile page placeholder', userInfo: req.user });
  324. });
  325.  
  326. module.exports = userRoutes;
  327. ```
  328.  
  329. We have a new auth helper method here. This, rather than redirecting logged in users, will redirect users that aren't logged in. We're protecting this route. Again, the auth helper is middleware. If the user isn't logged in, they get an error, if they are logged in, the helper function calls `next()` where, according to the route, they get redirected to a user profile page that includes their own user data, to be displayed. Add the following code to the `services/auth/auth-helpers` file:
  330.  
  331. ```javascript
  332. function loginRequired(req, res, next) {
  333. if (!req.user) res.redirect('/auth/login');
  334.  
  335. return next();
  336. }
  337.  
  338. module.exports = {
  339. comparePass,
  340. loginRedirect,
  341. loginRequired,
  342. createNewUser
  343. }
  344. ```
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement