1. 基于session的注册、登录、登出
session存储到数据库
新建user.js
,添加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)
实现注册、登录、登出功能
新建users.js
文件
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) } })
更改app.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优化冗余代码
正如上面的代码中有有许多重复的错误检查代码和重复的认证操作,可以使用Passport
中间价进行简化。Passport
支持不同的认证策略,如OpenID、OAuth、OAuth2.0等。在这里,使用Local Strategy
来简化用户名密码注册的认证方式。
更新user.js
,使用passport-local-mongoose
模块简化username
和password
存储
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 within our user model. 将注册用户的密码进行哈希加密。使用salt
为password加密,salt
是一个用来执行密码hash
操作的随机字符串。经hash加密后的密码存储在数据库中,原始的真实密码并没有被存储。当用户使用用户名密码进行认证时,密码经hash
后,与数据库中存储的密码进行比对。
所以,Passport-Local-Mongoose
在user model
上添加了认证方法,自动进行认证;基于用户名和密码的Local Strategy
认证方法可以通过user.authenticate
直接使用。
以用户名test,密码password为例,存储到mongoDB中的内容如下:
{ "_id" : ObjectId("5e69d49249cd2322286205b6"), "admin" : false, "username" : "test", "salt" : "706639aa4b1d0627629ca0372e3e945189c6d2c6f534dcead55518d13200127c", "hash" : "e9141ec79f2a0bcab0af3b4bc337c76b635e36f5cc3727f3d71e24224e559dda87e3e3e5f309d4220c50e1bc0fc10d2d78d007004e0076e81e43a9b05c3393bce5ca7f4de65bef0c40c4e9383aade96263a5a56ca81c9992e859e7e9f5daab2811df49fa897b731d313769c2f3bb2a73f7dd8bbb3c14b3bcf5088c57cb1439db03238f1d542dc56008b067f0061c5f0d91f0ce89c053180630c2e086ebb6fb7f5a26a67a4e5cabe63887beec82af6e757ebf945d727564ee09494d05f3b5fb05e33e718c01e44e7cef10344dd6b2ee02da9717ac410c8259ae752acf8d97e931cc6be2d32981af6c0a24c51fcdbde44dc44bb220abe09407dfadd5c6d3d7a5699ea35db46a3acb0e6881cca77ba2802a75e97f9be8c719792dfc9847e3f0af1b97a0152f1d772eea4c30a0a18e9dc5621bdab77255e958f509402aeb9a2b8238d78e72c46f3b08cb76425aa5ebcdbe80ec7541c3b6b394529be98eed96be5622366710db7388c599d3412dea143b233da9e429ded07bbd1159e41b8ab96a73f79ab15e5734a961c13e276445a8c2f28d315b0e48784918422709763871c1074ccbfc1d9841f88719d529ba0ab90d2d71b4db039213ffb4e072da7787f022564b1ad285b0512e2679edc461286b5c51deb0c0ec9cfbc4a70cecb8e531471a4adeff27b69d0cb0aec4b4f155d3a14d9f03af7f62428b3a895620aa26b3f4a67f09", "__v" : 0 } // 这里可没有存密码
新建authenticate.js
文件
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
中间件也支持sessions
,但有用户信息要序列化后与session
信息存储在服务端,收到请求后,用户信息需要反序列化从session
信息中提取出。Passport-Local-Mongoose
插件通过serializeUser
和deserializeUser
支持序列化和反序列化操作。
更改users.js
文件
... 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!'}) })
更改app.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() } } ...
来源:https://www.cnblogs.com/wydumn/p/12590664.html