├── .gitattributes ├── .gitignore ├── README.md ├── app └── routes.js ├── config ├── database.js └── passport.js ├── package.json ├── scripts └── create_database.js ├── server.js └── views ├── index.ejs ├── login.ejs ├── profile.ejs └── signup.ejs /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | 46 | [Dd]ebug/ 47 | [Rr]elease/ 48 | x64/ 49 | build/ 50 | [Bb]in/ 51 | [Oo]bj/ 52 | 53 | # MSTest test Results 54 | [Tt]est[Rr]esult*/ 55 | [Bb]uild[Ll]og.* 56 | 57 | *_i.c 58 | *_p.c 59 | *.ilk 60 | *.meta 61 | *.obj 62 | *.pch 63 | *.pdb 64 | *.pgc 65 | *.pgd 66 | *.rsp 67 | *.sbr 68 | *.tlb 69 | *.tli 70 | *.tlh 71 | *.tmp 72 | *.tmp_proj 73 | *.log 74 | *.vspscc 75 | *.vssscc 76 | .builds 77 | *.pidb 78 | *.log 79 | *.scc 80 | 81 | # Visual C++ cache files 82 | ipch/ 83 | *.aps 84 | *.ncb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | 101 | # TeamCity is a build add-in 102 | _TeamCity* 103 | 104 | # DotCover is a Code Coverage Tool 105 | *.dotCover 106 | 107 | # NCrunch 108 | *.ncrunch* 109 | .*crunch*.local.xml 110 | 111 | # Installshield output folder 112 | [Ee]xpress/ 113 | 114 | # DocProject is a documentation generator add-in 115 | DocProject/buildhelp/ 116 | DocProject/Help/*.HxT 117 | DocProject/Help/*.HxC 118 | DocProject/Help/*.hhc 119 | DocProject/Help/*.hhk 120 | DocProject/Help/*.hhp 121 | DocProject/Help/Html2 122 | DocProject/Help/html 123 | 124 | # Click-Once directory 125 | publish/ 126 | 127 | # Publish Web Output 128 | *.Publish.xml 129 | *.pubxml 130 | 131 | # NuGet Packages Directory 132 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 133 | #packages/ 134 | 135 | # Windows Azure Build Output 136 | csx 137 | *.build.csdef 138 | 139 | # Windows Store app package directory 140 | AppPackages/ 141 | 142 | # Others 143 | sql/ 144 | *.Cache 145 | ClientBin/ 146 | [Ss]tyle[Cc]op.* 147 | ~$* 148 | *~ 149 | *.dbmdl 150 | *.[Pp]ublish.xml 151 | *.pfx 152 | *.publishsettings 153 | 154 | # RIA/Silverlight projects 155 | Generated_Code/ 156 | 157 | # Backup & report files from converting an old project file to a newer 158 | # Visual Studio version. Backup files are not needed, because we have git ;-) 159 | _UpgradeReport_Files/ 160 | Backup*/ 161 | UpgradeLog*.XML 162 | UpgradeLog*.htm 163 | 164 | # SQL Server files 165 | App_Data/*.mdf 166 | App_Data/*.ldf 167 | 168 | ############# 169 | ## Windows detritus 170 | ############# 171 | 172 | # Windows image file caches 173 | Thumbs.db 174 | ehthumbs.db 175 | 176 | # Folder config file 177 | Desktop.ini 178 | 179 | # Recycle Bin used on file shares 180 | $RECYCLE.BIN/ 181 | 182 | # Mac crap 183 | .DS_Store 184 | 185 | 186 | ############# 187 | ## Python 188 | ############# 189 | 190 | *.py[co] 191 | 192 | # Packages 193 | *.egg 194 | *.egg-info 195 | dist/ 196 | build/ 197 | eggs/ 198 | parts/ 199 | var/ 200 | sdist/ 201 | develop-eggs/ 202 | .installed.cfg 203 | 204 | # Installer logs 205 | pip-log.txt 206 | 207 | # Unit test / coverage reports 208 | .coverage 209 | .tox 210 | 211 | #Translations 212 | *.mo 213 | 214 | #Mr Developer 215 | .mr.developer.cfg 216 | 217 | ###### 218 | # Idea 219 | ###### 220 | .idea/ 221 | 222 | ############## 223 | # node modules 224 | ############## 225 | node_modules/ 226 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Complete Guide to Node Authentication with MySQL 2 | 3 | ❤️ Visit [FullStack Framework 2023](https://github.com/manjeshpv/awesome-sandbox) 4 | 5 | Code for the entire scotch.io tutorial series: Complete Guide to Node Authentication with MongoDB 6 | 7 | Current version database is ported to MySQL 8 | 9 | We will be using Passport to authenticate users locally, 10 | 11 | ## Instructions 12 | 13 | If you would like to download the code and try it for yourself: 14 | 15 | 1. Clone the repo: `git clone git@github.com:manjeshpv/node-express-passport-mysql.git` 16 | 1. Install packages: `npm install` 17 | 1. Edit the database configuration: `config/database.js` 18 | 1. Create the database schema: `node scripts/create_database.js` 19 | 1. Launch: `node server.js` 20 | 1. Visit in your browser at: `http://localhost:8080` 21 | 22 | 23 | Licence: 1 24 | -------------------------------------------------------------------------------- /app/routes.js: -------------------------------------------------------------------------------- 1 | // app/routes.js 2 | module.exports = function(app, passport) { 3 | 4 | // ===================================== 5 | // HOME PAGE (with login links) ======== 6 | // ===================================== 7 | app.get('/', function(req, res) { 8 | res.render('index.ejs'); // load the index.ejs file 9 | }); 10 | 11 | // ===================================== 12 | // LOGIN =============================== 13 | // ===================================== 14 | // show the login form 15 | app.get('/login', function(req, res) { 16 | 17 | // render the page and pass in any flash data if it exists 18 | res.render('login.ejs', { message: req.flash('loginMessage') }); 19 | }); 20 | 21 | // process the login form 22 | app.post('/login', passport.authenticate('local-login', { 23 | successRedirect : '/profile', // redirect to the secure profile section 24 | failureRedirect : '/login', // redirect back to the signup page if there is an error 25 | failureFlash : true // allow flash messages 26 | }), 27 | function(req, res) { 28 | console.log("hello"); 29 | 30 | if (req.body.remember) { 31 | req.session.cookie.maxAge = 1000 * 60 * 3; 32 | } else { 33 | req.session.cookie.expires = false; 34 | } 35 | res.redirect('/'); 36 | }); 37 | 38 | // ===================================== 39 | // SIGNUP ============================== 40 | // ===================================== 41 | // show the signup form 42 | app.get('/signup', function(req, res) { 43 | // render the page and pass in any flash data if it exists 44 | res.render('signup.ejs', { message: req.flash('signupMessage') }); 45 | }); 46 | 47 | // process the signup form 48 | app.post('/signup', passport.authenticate('local-signup', { 49 | successRedirect : '/profile', // redirect to the secure profile section 50 | failureRedirect : '/signup', // redirect back to the signup page if there is an error 51 | failureFlash : true // allow flash messages 52 | })); 53 | 54 | // ===================================== 55 | // PROFILE SECTION ========================= 56 | // ===================================== 57 | // we will want this protected so you have to be logged in to visit 58 | // we will use route middleware to verify this (the isLoggedIn function) 59 | app.get('/profile', isLoggedIn, function(req, res) { 60 | res.render('profile.ejs', { 61 | user : req.user // get the user out of session and pass to template 62 | }); 63 | }); 64 | 65 | // ===================================== 66 | // LOGOUT ============================== 67 | // ===================================== 68 | app.get('/logout', function(req, res) { 69 | req.logout(); 70 | res.redirect('/'); 71 | }); 72 | }; 73 | 74 | // route middleware to make sure 75 | function isLoggedIn(req, res, next) { 76 | 77 | // if user is authenticated in the session, carry on 78 | if (req.isAuthenticated()) 79 | return next(); 80 | 81 | // if they aren't redirect them to the home page 82 | res.redirect('/'); 83 | } 84 | -------------------------------------------------------------------------------- /config/database.js: -------------------------------------------------------------------------------- 1 | // config/database.js 2 | module.exports = { 3 | 'connection': { 4 | 'host': 'localhost', 5 | 'user': 'root', 6 | 'password': 'password' 7 | }, 8 | 'database': 'my_schema', 9 | 'users_table': 'users' 10 | }; -------------------------------------------------------------------------------- /config/passport.js: -------------------------------------------------------------------------------- 1 | // config/passport.js 2 | 3 | // load all the things we need 4 | var LocalStrategy = require('passport-local').Strategy; 5 | 6 | // load up the user model 7 | var mysql = require('mysql'); 8 | var bcrypt = require('bcrypt-nodejs'); 9 | var dbconfig = require('./database'); 10 | var connection = mysql.createConnection(dbconfig.connection); 11 | connection.connect(); 12 | connection.query('USE ' + dbconfig.database); 13 | connection.end(); 14 | // expose this function to our app using module.exports 15 | module.exports = function(passport) { 16 | 17 | // ========================================================================= 18 | // passport session setup ================================================== 19 | // ========================================================================= 20 | // required for persistent login sessions 21 | // passport needs ability to serialize and unserialize users out of session 22 | 23 | // used to serialize the user for the session 24 | passport.serializeUser(function(user, done) { 25 | done(null, user.id); 26 | }); 27 | 28 | // used to deserialize the user 29 | passport.deserializeUser(function(id, done) { 30 | connection.connect(); 31 | connection.query("SELECT * FROM users WHERE id = ? ",[id], function(err, rows){ 32 | done(err, rows[0]); 33 | }); 34 | connection.end(); 35 | }); 36 | 37 | // ========================================================================= 38 | // LOCAL SIGNUP ============================================================ 39 | // ========================================================================= 40 | // we are using named strategies since we have one for login and one for signup 41 | // by default, if there was no name, it would just be called 'local' 42 | 43 | passport.use( 44 | 'local-signup', 45 | new LocalStrategy({ 46 | // by default, local strategy uses username and password, we will override with email 47 | usernameField : 'username', 48 | passwordField : 'password', 49 | passReqToCallback : true // allows us to pass back the entire request to the callback 50 | }, 51 | function(req, username, password, done) { 52 | // find a user whose email is the same as the forms email 53 | // we are checking to see if the user trying to login already exists 54 | connection.connect(); 55 | connection.query("SELECT * FROM users WHERE username = ?",[username], function(err, rows) { 56 | if (err) 57 | return done(err); 58 | if (rows.length) { 59 | return done(null, false, req.flash('signupMessage', 'That username is already taken.')); 60 | } else { 61 | // if there is no user with that username 62 | // create the user 63 | var newUserMysql = { 64 | username: username, 65 | password: bcrypt.hashSync(password, null, null) // use the generateHash function in our user model 66 | }; 67 | 68 | var insertQuery = "INSERT INTO users ( username, password ) values (?,?)"; 69 | connection.connect(); 70 | connection.query(insertQuery,[newUserMysql.username, newUserMysql.password],function(err, rows) { 71 | newUserMysql.id = rows.insertId; 72 | 73 | return done(null, newUserMysql); 74 | }); 75 | connection.end(); 76 | } 77 | }); 78 | connection.end(); 79 | }) 80 | ); 81 | 82 | // ========================================================================= 83 | // LOCAL LOGIN ============================================================= 84 | // ========================================================================= 85 | // we are using named strategies since we have one for login and one for signup 86 | // by default, if there was no name, it would just be called 'local' 87 | 88 | passport.use( 89 | 'local-login', 90 | new LocalStrategy({ 91 | // by default, local strategy uses username and password, we will override with email 92 | usernameField : 'username', 93 | passwordField : 'password', 94 | passReqToCallback : true // allows us to pass back the entire request to the callback 95 | }, 96 | function(req, username, password, done) { // callback with email and password from our form 97 | connection.connect(); 98 | connection.query("SELECT * FROM users WHERE username = ?",[username], function(err, rows){ 99 | if (err) 100 | return done(err); 101 | if (!rows.length) { 102 | return done(null, false, req.flash('loginMessage', 'No user found.')); // req.flash is the way to set flashdata using connect-flash 103 | } 104 | 105 | // if the user is found but the password is wrong 106 | if (!bcrypt.compareSync(password, rows[0].password)) 107 | return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.')); // create the loginMessage and save it to session as flashdata 108 | 109 | // all is well, return successful user 110 | return done(null, rows[0]); 111 | }); 112 | connection.end(); 113 | }) 114 | ); 115 | }; 116 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-authentication", 3 | "main": "server.js", 4 | "scripts": { 5 | "start": "node ./server" 6 | }, 7 | "dependencies": { 8 | "bcrypt-nodejs": "0.0.3", 9 | "body-parser": "^1.13.1", 10 | "connect-flash": "^0.1.1", 11 | "cookie-parser": "^1.3.5", 12 | "ejs": "^2.3.2", 13 | "express": "^4.13.0", 14 | "express-session": "^1.11.3", 15 | "morgan": "^1.6.0", 16 | "mysql": "^2.7.0", 17 | "passport": "^0.2.2", 18 | "passport-local": "^1.0.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /scripts/create_database.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by barrett on 8/28/14. 3 | */ 4 | 5 | var mysql = require('mysql'); 6 | var dbconfig = require('../config/database'); 7 | 8 | var connection = mysql.createConnection(dbconfig.connection); 9 | 10 | connection.query('CREATE DATABASE ' + dbconfig.database); 11 | 12 | connection.query('\ 13 | CREATE TABLE `' + dbconfig.database + '`.`' + dbconfig.users_table + '` ( \ 14 | `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, \ 15 | `username` VARCHAR(20) NOT NULL, \ 16 | `password` CHAR(60) NOT NULL, \ 17 | PRIMARY KEY (`id`), \ 18 | UNIQUE INDEX `id_UNIQUE` (`id` ASC), \ 19 | UNIQUE INDEX `username_UNIQUE` (`username` ASC) \ 20 | )'); 21 | 22 | console.log('Success: Database Created!') 23 | 24 | connection.end(); 25 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | // server.js 2 | 3 | // set up ====================================================================== 4 | // get all the tools we need 5 | var express = require('express'); 6 | var session = require('express-session'); 7 | var cookieParser = require('cookie-parser'); 8 | var bodyParser = require('body-parser'); 9 | var morgan = require('morgan'); 10 | var app = express(); 11 | var port = process.env.PORT || 8080; 12 | 13 | var passport = require('passport'); 14 | var flash = require('connect-flash'); 15 | 16 | // configuration =============================================================== 17 | // connect to our database 18 | 19 | require('./config/passport')(passport); // pass passport for configuration 20 | 21 | 22 | 23 | // set up our express application 24 | app.use(morgan('dev')); // log every request to the console 25 | app.use(cookieParser()); // read cookies (needed for auth) 26 | app.use(bodyParser.urlencoded({ 27 | extended: true 28 | })); 29 | app.use(bodyParser.json()); 30 | 31 | app.set('view engine', 'ejs'); // set up ejs for templating 32 | 33 | // required for passport 34 | app.use(session({ 35 | secret: 'vidyapathaisalwaysrunning', 36 | resave: true, 37 | saveUninitialized: true 38 | } )); // session secret 39 | app.use(passport.initialize()); 40 | app.use(passport.session()); // persistent login sessions 41 | app.use(flash()); // use connect-flash for flash messages stored in session 42 | 43 | 44 | // routes ====================================================================== 45 | require('./app/routes.js')(app, passport); // load our routes and pass in our app and fully configured passport 46 | 47 | // launch ====================================================================== 48 | app.listen(port); 49 | console.log('The magic happens on port ' + port); 50 | -------------------------------------------------------------------------------- /views/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 |Login or Register with:
18 | 19 | Local Login 20 | Local Signup 21 |
28 | id: <%= user.id %>
29 | username: <%= user.username %>
30 | password: <%= user.password %>
31 |