📜  当数据库中的密码存储在 Node.js 中以散列形式存储时,如何使用原始密码登录?

📅  最后修改于: 2022-05-13 01:56:37.397000             🧑  作者: Mango

当数据库中的密码存储在 Node.js 中以散列形式存储时,如何使用原始密码登录?

出于安全原因,存储在数据库中的密码始终采用(散列+盐)形式。当用户在任何网站上注册时,都会以原始形式给出密码。但是将原始密码直接存储在数据库中并不是一个好习惯。使用一些服务器端逻辑,我们首先将原始密码转换为(散列+盐)形式,然后将其存储在数据库中。这带来了一个新的挑战,如何比较用户在登录时给出的原始密码,并根据密码是否正确授予用户访问权限。

密码以下列形式存储在数据库中:

Hashed(password, salt) 

例子:

设置逻辑以使用原始密码登录的步骤:

  • 在用户提供的唯一用户名或电子邮件的帮助下搜索数据库以登录。
  • 查找唯一记录,如果未找到,则返回“用户不存在”。
  • 在 ' 处拆分加密密码 ' 单独查找散列密码和盐。
  • 散列用户提供的原始密码,以使用盐使用 Node.js 'scrypt' 方法登录。
  • 将得到的散列值与拆分数据库密码得到的散列值进行比较。
  • 如果两个哈希值相等,则用户登录并授予访问权限。
  • 如果两者的哈希值不相等,则拒绝访问并显示无效密码消息。

注意:为了说明逻辑,这里我们采用本地或自定义数据库。同样的逻辑也可以用MongoDB、MySql等常规数据库来实现。

示例:此示例说明了当数据库中存储的密码为(散列+盐)形式时如何使用原始密码登录。

javascript
const util = require('util')
const crypto = require('crypto')
const express = require('express')
const bodyParser = require('body-parser')
const repo = require('./repository')
 
const app = express()
const scrypt = util.promisify(crypto.scrypt)
const port = process.env.PORT || 3000
 
// The body-parser middleware to parse form data
app.use(bodyParser.urlencoded({ extended: true }))
 
// Get route to display HTML form to sign in
app.get('/signin', (req, res) => {
    res.send(`
    
      
        
          
                       
                   
        
          
                       
                   
        
                   
      
    
  `) })   // Post route to handle form submission logic and app.post('/signin', async (req, res) => {       // Email and password submitted by the user     const { email, password } = req.body       // Find record by given unique username or email     const user = await repo.findBy({ email })     console.log(user)       // If record not found by given username     if (!user) {         return res.send('User Not Exist')     }       // Hashed and salt of database password     const [hashed, salt] = user.password.split('.')       // Hashing raw password submitted by the user     // to sign in third argument is the key length     // that must be same when hashing the password     // to store it into the database when user sign up     const hashedBuff = await scrypt(password, salt, 64)     console.log(hashed)     console.log(hashedBuff.toString('hex'))       // Compare saved hashed of database and     // obtained hashed     const isValid = hashed === hashedBuff.toString('hex')       if (isValid) {         return res.send('Sign In successfully')     }     return res.send('Invalid Password') })   // Server setup app.listen(port, () => {     console.log(`Server start on port ${port}`) })


javascript
// Importing node.js file system, util,
// crypto module
const fs = require('fs')
const util = require('util')
const crypto = require('crypto')
 
// Convert callback based scrypt method
// to promise based method
const scrypt = util.promisify(crypto.scrypt)
 
class Repository {
 
    constructor(filename) {
 
        // The filename where datas are
        // going to store
        if (!filename) {
            throw new Error(
'Filename is required to create a datastore!')
        }
 
        this.filename = filename
 
        try {
            fs.accessSync(this.filename)
        } catch (err) {
 
            // If file not exist it is created
            // with empty array
            fs.writeFileSync(this.filename, '[]')
        }
    }
 
    async findBy(attrs) {
 
        // Read all file contents of the datastore
        const jsonRecords = await
            fs.promises.readFile(this.filename, {
            encoding: 'utf8'
        })
 
        // Parsing json records in javascript
        // object type records
        const records = JSON.parse(jsonRecords)
 
        // Iterating through each record
        for (let record of records) {
            let found = true
 
            // Iterate through each given
            // propert for each record
            for (let key in attrs) {
 
                // If any given property not matches
                // with record record is discarded
                if (record[key] !== attrs[key]) {
                    found = false
                }
            }
            // If 'found' remains true after iterating
            // through each given property that
            // means record found
            if (found) {
                return record
            }
        }
    }
}
 
// The 'datastore.json' file created at runtime
// if it not exist, here we try to fetch
// information from database using some properties
// that means database(datastore.json) already
// exist and there are also records in it.
module.exports = new Repository('datastore.json')


文件名:repository.js该文件包含与创建本地数据库以及如何与之交互相关的所有逻辑。

javascript

// Importing node.js file system, util,
// crypto module
const fs = require('fs')
const util = require('util')
const crypto = require('crypto')
 
// Convert callback based scrypt method
// to promise based method
const scrypt = util.promisify(crypto.scrypt)
 
class Repository {
 
    constructor(filename) {
 
        // The filename where datas are
        // going to store
        if (!filename) {
            throw new Error(
'Filename is required to create a datastore!')
        }
 
        this.filename = filename
 
        try {
            fs.accessSync(this.filename)
        } catch (err) {
 
            // If file not exist it is created
            // with empty array
            fs.writeFileSync(this.filename, '[]')
        }
    }
 
    async findBy(attrs) {
 
        // Read all file contents of the datastore
        const jsonRecords = await
            fs.promises.readFile(this.filename, {
            encoding: 'utf8'
        })
 
        // Parsing json records in javascript
        // object type records
        const records = JSON.parse(jsonRecords)
 
        // Iterating through each record
        for (let record of records) {
            let found = true
 
            // Iterate through each given
            // propert for each record
            for (let key in attrs) {
 
                // If any given property not matches
                // with record record is discarded
                if (record[key] !== attrs[key]) {
                    found = false
                }
            }
            // If 'found' remains true after iterating
            // through each given property that
            // means record found
            if (found) {
                return record
            }
        }
    }
}
 
// The 'datastore.json' file created at runtime
// if it not exist, here we try to fetch
// information from database using some properties
// that means database(datastore.json) already
// exist and there are also records in it.
module.exports = new Repository('datastore.json')

使用以下命令运行index.js文件:

node index.js

文件名:package.json

包.json 文件

数据库:

数据库

输出:

在这里,我们分别使用不同的用户名和密码组合提交三个表单,并分别获得如图所示的输出。

使用无效的用户名登录

使用有效的用户名但无效的密码登录

使用有效的用户名和密码登录

重定向页面:

使用无效用户名登录时的响应

使用有效用户名但密码无效登录时的响应

使用有效的用户名和密码登录时的响应