網站註冊與登陸使用 bcrypt與 passport 雙重驗證 解釋 bcrypt 安裝不成功解決辦法

網站在登陸前,須要進行註冊收集用戶基本信息,bcrypt 提供密碼加密驗證的方法,可是使用不正確,會給初學者帶來各類問題。html

bcrypt 的安裝:node

npm i bcrypt

通過測試,常常安裝不成功,緣由和node.js的版本有緣由,我在 下面這篇文章中有記錄解決辦法:算法

bcrypt 安裝不成功解決辦法

但也不是萬能的,若是還不能解決的話,能夠嘗試給 bcrypt 指定版本號安裝:mongodb

npm install --save bcrypt@2.0.1

通常是會成功的!!數據庫

 

用戶在註冊時,除了收集用戶信息外,由於要用到 bcrypt ,必需要在註冊時對密碼進行加密,加密後再保存到數據庫中。由於用戶登陸時,使用 bcrypt 的 compare 方法,這個方法是驗證加密的密碼的,若是在註冊時沒有加密,而登陸時使用 compare 進行驗證,直接會致使,將 mongodb 直接掛掉!並且登陸也不會成功,也不報錯,也不提示的這種尷尬的局面,會致使無從下手。express

bcrypt  註冊的邏輯:npm

  1. 收集用戶(表單)的基本信息
  2. bcrypt.genSalt() 給密碼加密
  3. 加密完成,將數據保存在數據庫
router.post('/register',urlencodedParser,(req,res) => {
    //驗證
    
    const newUser = new UserSchema({
        email: req.body.email,
        password:req.body.password,
        confirmPassword:req.body.confirmPassword,
        firstName:req.body.firstName,
        lastName:req.body.lastName
    });

    console.log('body:  ' + newUser)

    //給 newUser.password 加密,hash 爲加密後的密碼
    bcrypt.genSalt(10, function(err, salt) {
        bcrypt.hash(newUser.password, salt, (err, hash) => {
            if(err) throw err;
            
            newUser.password = hash;

            //保存到數據庫
            newUser.save().then((user) => {
                res.redirect('/admin/login');
                res.send(user);
            }).catch((err) => {
                res.render('/admin/register',{})
            })
        });
    });
});
res.redirect() 爲跳轉到哪一個路徑
註冊成功以後,直接跳轉到 login 頁面。

登陸相對比較複雜,會用到
passport 與 bcrypt 進行驗證。
  • passport 功能單一,支持本地帳號驗證和第三方帳號登陸驗證,這裏用到了本地用戶登陸驗證。它自己不能做驗證,它主要是用來驗證請求的,是由 passport 與 local-passport 搭配使用的。
  • bcrypt 是單向的,跨平臺的文件加密工具,通過它加密的密碼,口令爲8~56個字符,並在內容被轉化爲 448 位的密鑰,在加密算法領域,越慢的加密算法越安全,bcrypt 比 md5 還要慢,所以它的算法是比較安全的,黑客破解成本高。因 bcrypt 是單向的,受攻擊破解的機率大大下降。

登陸方法也能夠不使用 passport 登陸賬號驗證,僅使用 bcrypt 進行密碼驗證:安全

const express = require('express');
const router = express.Router();
const bodyParser = require('body-parser');
const bcrypt = require('bcrypt');
const urlencodedParser = bodyParser.urlencoded({ extended: false });

require('../models/UserSchema');
const UserSchema = mongoose.model('users');

router.post("/login",urlencodedParser,(req,res,next) => {
    const loginUser = {
        email:req.body.email,
        password:req.body.password
    };

    console.log(loginUser);


     UserSchema.findOne({
         email:loginUser.email
       }).then(users => {if(!users){
           return done(null, false, {message: 'No User Found'});
        } 
       //驗證密碼
         bcrypt.compare(loginUser.password, users.password, (err, isMatch) => {
          if(err) throw err;
          if(isMatch){
           res.redirect('/')
         } else {
           res.redirect('/admin/login')
          }
        })
      })
  });

同時使用 passport 與 bcrypt 進行驗證:session

npm install passport --save
npm install passport-local --save

默認本地驗證是經過用戶名和密碼來進行驗證的,須要對 Strategies 進行配置:mongoose

assport.use(new LocalStrategy(
      function(username, password, done) {
          //操做
    })
})

我這個項目是使用郵箱和密碼來進行驗證的,方法有所不一樣:

passport.use(new LocalStrategy({usernameField: 'email'}, (email, password, done) => {
    //操做
  }))
LocalStrategy 的第一個參數對象爲一個字符串,用來講明是用戶驗證是的是一個 email;
          第二個參數是從 passport 方法中獲取並傳回來的表單中的值,也就是要驗證的字段。
          第二個參數中的 done 爲驗證回調,在passport.use()裏面,done()有三種用法
  • 當發生系統級異常時,返回done(err),這裏是數據庫查詢出錯
  • 當驗證不經過時,返回done(null, false, message),這裏的message是可選的,可經過express-flash調用。express-flash 爲驗證提示信息:登陸成功 / 登陸失敗
  • 當驗證經過時,返回done(null, user)

login 在這裏的登陸方法,登陸過程當中的密碼驗證在 passport.js 中一塊兒操做:

const express = require('express');
const router = express.Router();
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const bcrypt = require('bcrypt');
const passport = require('passport');

const urlencodedParser = bodyParser.urlencoded({ extended: false });


router.post("/login",urlencodedParser,(req,res,next) => { const loginUser = { email:req.body.email, password:req.body.password }; console.log(loginUser); passport.authenticate('local', { successRedirect:'/', failureRedirect: '/admin/login', failureFlash: true })(req, res, next); })

這裏的passport.authenticate(‘local’)就是中間件,若經過就進入後面的回調函數,而且給res加上res.user,若不經過則默認返回401錯誤。

authenticate()方法有3個參數,第一是name,即驗證策略的名稱,第二個是options,包括下列屬性:

  • session:Boolean。設置是否須要session,默認爲true
  • successRedirect:String。設置當驗證成功時的跳轉連接
  • failureRedirect:String。設置當驗證失敗時的跳轉連接
  • failureFlash:Boolean or String。設置爲Boolean時,express-flash將調用use()裏設置的message。設置爲String時將直接調用這裏的信息。
  • successFlash:Boolean or String。使用方法同上。

第三個參數是callback。

 
 
const LocalStrategy = require('passport-local').Strategy;
const bcrypt = require('bcrypt');

// Load user model
const UserSchema = require('../models/UserSchema');
 
module.exports = function(passport){
  passport.use(new LocalStrategy({usernameField: 'email'}, (email, password, done) => {
  console.log('獲取的字段:' + email+'/'+ password)
   // Match user
  UserSchema.findOne({
    email:email
  }).then(users => {
    console.log('user存在嗎?' + users)
    if(!users){
      return done(null, false, {message: 'No User Found'});
    }

   // Match password
  bcrypt.compare(password, users.password, (err, isMatch) => {
    console.log('password ' + password);
    console.log('user.password' + users.password);
    if(err) throw err;
    if(isMatch){
      console.log('isMatch ' + isMatch)
      return done(null, users);
    } else {
      return done(null, false, {message: 'Password Incorrect'});
    }
  })
 })
}));


/*
*下面兩個方法是用來對數據進行序列化的 * serializeUser 將users.id序列化到session中 * deserializeUser 若id存在則從數據庫中查詢users並存儲與req.users中 * * 此處的 users 爲表名 */ passport.serializeUser(function(users, done) { done(null, users.id); }); passport.deserializeUser(function(id, done) { UserSchema.findById(id, function(err, users) { done(err, users); }); }); }

 

登陸驗證方法尚未徹底搞懂,若是哪裏有不對的地方,歡迎指正。

相關文章
相關標籤/搜索