• session存储到MongoDB


    1. 基于session的注册、登录、登出

    session存储到数据库

    新建user.js,添加usersmongoose 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模块简化usernamepassword存储

    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-Mongooseuser 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插件通过serializeUserdeserializeUser支持序列化和反序列化操作。

    更改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()
        }
    }
    ...
    
  • 相关阅读:
    Linux下如何查看版本信息
    java单利模式设计
    MIT 2012 分布式课程基础源码解析-底层通讯实现
    MIT 2012分布式课程基础源码解析-事件管理封装
    MIT 2012分布式课程基础源码解析-线程池实现
    MIT 2012分布式课程基础源码解析一-源码概述
    Leetcode按Tag刷题
    网页搜集系统
    c/c++中的各种字符串转换
    gentoo装X服务器时显卡选择
  • 原文地址:https://www.cnblogs.com/wydumn/p/12590664.html
Copyright © 2020-2023  润新知