1. Based session of registration, login, logout
session stored in the database
New user.js
, add users
mongoose model
var mongoose = require('mongoose')
var Schema = mongoose.Schema
var User = new Schema({
username: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
admin: {
type: Boolean,
default: false
}
})
module.exports = mongoose.model('User', User)
Achieve registration, login, logout function
New users.js
file
var express = require('express')
const bodyParser = require('body-parser')
var User = require('user.js')
var router = express.Router()
router.use(bodyParser.json())
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
router.post('/signup', (req, res, next) => {
User.findOne({username: req.body.username})
.then((user) => {
if (user != null) { // 注册用户已存在
var err = new Error('User ' + req.body.username + ' already exists!')
err.status = 403
next(err)
} else { // 没有该用户
return User.create({
username: req.body.username,
password: req.body.password
})
}
})
.then((user) => {
res.statusCode = 200
res.setHeader('Content-Type', 'application/json')
res.json({status: 'Registration Successful!', user: user})
}, (err) => next(err))
.catch((err) => next(err))
})
router.post('/login', (req, res, next) => {
if(!req.session.user) {
var authHeader = req.headers.authorization
if (!authHeader) {
var err = new Error('You are not authenticated!')
res.setHeader('WWW-Authenticate', 'Basic')
err.status = 401
return next(err)
}
var auth = new Buffer.from(authHeader.split(' ')[1], 'base64').toString().split(':')
var username = auth[0]
var password = auth[1]
User.findOne({username: username})
.then((user) => {
if (user === null) {
var err = new Error('User ' + username + ' does not exist!')
err.status = 403
return next(err)
} else if (user.password !== password) {
var err = new Error('Your password is incorrect!')
err.status = 403
return next(err)
} else if(user.username === username && user.password === password) {
req.session.user = 'authenticated'
req.statusCode = 200
res.setHeader('Content-Type', 'text/plain')
res.end('You are authenticated!')
}
})
.catch((err) => next(err))
} else {
res.statusCode = 200
res.setHeader('Content-Type', 'text/plain')
res.end('You are authenticated!')
}
})
router.get('/logout', (req, res) => {
if (req.session) {
req.session.destroy() // 删除session
res.clearCookie('session-id') // 清除客户端的cookie
res.redirect('/') // 重定向到应用主页
} else {
var err = new Error('You are not logged in!')
err.status = 403
next(err)
}
})
changeapp.js
...
app.use('/', indexRouter)
app.use('/users', usersRouter)
function basicAuth(req, res, next) {
if (!req.session.user) {
var err = new Error('You are not authenticated!')
err.status = 403
return next(err)
} else {
if (req.session.user === 'authenticated') {
next()
} else {
var err = new Error('You are not authenticated!')
err.status = 403
return next(err)
}
}
}
...
2. Passport redundant code optimization
As the above code has many repeated error checking code and repeat the authentication operation, using Passport
the central parity simplified. Passport
It supports different authentication policies, such as OpenID, OAuth, OAuth2.0 and so on. Here, we use Local Strategy
to simplify the authentication username and password registered.
Updating user.js
, using passport-local-mongoose
modules to simplify username
and password
storage
var passportLocalMongoose = require('passport-local-mongoose')
var User = new Schema({
admin: {
type: Boolean,
default: false
}
})
User.plugin(passportLocalMongoose)
passport-local-mongoose
plugin adds in the username and a encrypted way of storing the password. The password hash registered users encrypted within our user model. Use salt
of password encryption, salt
is used to perform a cryptographic hash
random string operation. By storing the password hash encrypted in the database, the original real password is not stored. When a user using a user name and password for authentication by password hash
after, to compare with the password stored in the database.
Therefore, Passport-Local-Mongoose
in user model
the method of adding authentication, authentication is automated; based on user name and password Local Strategy
by the authentication method user.authenticate
to be used directly.
User name test, password password, for example, stored in the content mongoDB as follows:
{
"_id" : ObjectId("5e69d49249cd2322286205b6"),
"admin" : false,
"username" : "test",
"salt" : "706639aa4b1d0627629ca0372e3e945189c6d2c6f534dcead55518d13200127c",
"hash" : "e9141ec79f2a0bcab0af3b4bc337c76b635e36f5cc3727f3d71e24224e559dda87e3e3e5f309d4220c50e1bc0fc10d2d78d007004e0076e81e43a9b05c3393bce5ca7f4de65bef0c40c4e9383aade96263a5a56ca81c9992e859e7e9f5daab2811df49fa897b731d313769c2f3bb2a73f7dd8bbb3c14b3bcf5088c57cb1439db03238f1d542dc56008b067f0061c5f0d91f0ce89c053180630c2e086ebb6fb7f5a26a67a4e5cabe63887beec82af6e757ebf945d727564ee09494d05f3b5fb05e33e718c01e44e7cef10344dd6b2ee02da9717ac410c8259ae752acf8d97e931cc6be2d32981af6c0a24c51fcdbde44dc44bb220abe09407dfadd5c6d3d7a5699ea35db46a3acb0e6881cca77ba2802a75e97f9be8c719792dfc9847e3f0af1b97a0152f1d772eea4c30a0a18e9dc5621bdab77255e958f509402aeb9a2b8238d78e72c46f3b08cb76425aa5ebcdbe80ec7541c3b6b394529be98eed96be5622366710db7388c599d3412dea143b233da9e429ded07bbd1159e41b8ab96a73f79ab15e5734a961c13e276445a8c2f28d315b0e48784918422709763871c1074ccbfc1d9841f88719d529ba0ab90d2d71b4db039213ffb4e072da7787f022564b1ad285b0512e2679edc461286b5c51deb0c0ec9cfbc4a70cecb8e531471a4adeff27b69d0cb0aec4b4f155d3a14d9f03af7f62428b3a895620aa26b3f4a67f09",
"__v" : 0
}
// 这里可没有存密码
New authenticate.js
file
var passport = require('passport')
// passport-local支持用户名密码的local strategy认证
var LocalStrategy = require('passport-local').Strategy
var User = require('user')
exports.local = passport.use(new LocalStrategy(User.authenticate()))
passport.serializeUser(User.serializeUser())
passport.deserializeUser(User.deserializeUser())
Passport
Middleware also supports sessions
, but the user information to be serialized and session
the information stored in the server, receiving the request, the user information need deserialized from session
the extracted information. Passport-Local-Mongoose
Plugin serializeUser
and deserializeUser
support serialization and de-serialization operation.
Change the users.js
file
...
var passport = require('passport')
...
router.post('/signup', (req, res, next) => {
User.register(new User({username: req.body.username}), req.body.password, (err, user) => {
if (err) {
res.statusCode = 500
res.setHeader('Content-Type', 'application/json')
res.json({err: err})
} else {
passport.authenticate('local')(req, res, () => {
res.statusCode = 200
res.setHeader('Content-Type', 'application/json')
res.json({success: true, status: 'Registration Successful!'})
})
}
})
})
router.post('/login', passport.authenticate('local'), (req, res) => {
res.statusCode = 200
res.setHeader('Content-Type', 'application/json')
res.json({success: true, status: 'You are successfully logged in!'})
})
changeapp.js
...
var passport = require('passport')
var authenticate = require('./authenticate')
...
app.use(passport.initialize())
app.use(passport.session())
...
function basicAuth(req, res, next) {
console.log(req.user)
if(!req.user) {
var err = new Error('You are not authenticated!')
err.status = 403
next(err)
} else {
next()
}
}
...