基于node對(duì)客戶端傳遞數(shù)據(jù)進(jìn)行加密儲(chǔ)存并返回token || express(三)

  • 上篇對(duì)客戶端的值進(jìn)行了增刪改查,但并沒有進(jìn)行數(shù)據(jù)安全性問題處理與身份驗(yàn)證

1 . 登錄后返回token字段,并對(duì)其他接口進(jìn)行身份驗(yàn)證

1.1導(dǎo)入校驗(yàn)包定義密匙與token有效時(shí)間
  • 下載express-jwtjsonwebtoken兩個(gè)包
// 一定要在接口之前配置解析 Token 的中間件
const expressJWT = require('express-jwt')
// 導(dǎo)入生成 Token 的包
const jwt = require('jsonwebtoken')
1.2 定義token密匙/不加權(quán)限的接口
// unless  定義的都是不加權(quán)限的接口  會(huì)忽略開頭為api  或者  user的接口   除此兩種都需在請(qǐng)求頭攜帶token
app.use(
  expressJWT({ secret: '服務(wù)端私有密匙(自己定義)', algorithms: ['HS256'] }).unless({
    path: [/^\/api||user/],
  })
)
1.3 定義身份驗(yàn)證錯(cuò)誤級(jí)別的中間件
// 定義錯(cuò)誤級(jí)別的中間件
app.use((err, req, res, next) => {
  // 身份認(rèn)證失敗后的錯(cuò)誤
  if (err.name === 'UnauthorizedError') return res.cc('身份認(rèn)證失??!')
  // 未知的錯(cuò)誤
  res.cc(err)
})
1.4 改造登錄接口返回token標(biāo)識(shí)
// 登錄接口
app.post('/api', (req, res) => {
  const body = req.body
  // 查詢登錄用戶名/密碼數(shù)據(jù)庫是否存在,并匹配
  let sqlapi = 'select * from ev_users where username = ? && password = ?'
  sql.query(sqlapi, [body.username, body.password], (err, result) => {
    console.log(result)
    if (err) return res.cc('服務(wù)端錯(cuò)誤')
    if (!result.length) return res.cc('用戶名/密碼錯(cuò)誤')
    const user = { ...result[0], password: '', user_pic: '' }
    // 對(duì)用戶的信息進(jìn)行加密,生成 Token 字符串
    // expiresIn代表token有效時(shí)間
    const tokenStr = jwt.sign(user, '服務(wù)端私有密匙(自己定義)', {
      expiresIn: '10h',
    })
    res.send({
      status: '200',
      data: 'ok',
      message: '登錄成功',
      token: 'Bearer ' + tokenStr,
    })
  })
})

2 . 對(duì)用戶數(shù)據(jù)進(jìn)行加密儲(chǔ)存

  • 此處用的是bcrypt不可逆,如需可破解的請(qǐng)用md5進(jìn)行加密
  • 下載bcryptjs
// 導(dǎo)入 bcryptjs 這個(gè)包
const bcrypt = require('bcryptjs')
// 注冊(cè)接口
app.post('/user', (req, res) => {
  const body = req.body
  // 查詢數(shù)據(jù)庫 *(所有) 表單為 ev_users 里 所有username   ? 為占位符代表?xiàng)l件
  const query = 'select * from ev_users where username=?'
  // ()  第一位為sql
  sql.query(query, body.username, (err, result) => {
    // err 為執(zhí)行錯(cuò)誤信息    result為數(shù)據(jù)
    if (err) return res.cc(err)
    // 判斷影響行數(shù)  能查詢到證明數(shù)據(jù)庫表單里存在這個(gè)值
    if (result.length > 0)  return res.cc('用戶名已存在')
    // 調(diào)用 bcrypt.hashSync() 對(duì)密碼進(jìn)行加密  10代表鹽的長(zhǎng)度
    body.password = bcrypt.hashSync(body.password, 10)
    // 插入數(shù)據(jù)
    const sqlint = 'insert into ev_users set ?'
    
    sql.query(
      sqlint,
      { username: body.username, password: body.password },
      (err, result) => {
        if (err) return res.cc(err)
        if(!result.affectedRows) return res.cc('注冊(cè)失敗')
        res.send({
          status: 200,
          data: 'ok',
          message: '注冊(cè)成功',
        })
      }
    )
  })
})

// 登錄接口進(jìn)行了修改  注釋掉的為以前未進(jìn)行加密時(shí)的處理方式
// 登錄接口
app.post('/api', (req, res) => {
  const body = req.body
  // 查詢登錄用戶名/密碼數(shù)據(jù)庫是否存在,并匹配
  // let sqlapi = 'select * from ev_users where username = ? && password = ?'
  let sqlapi = 'select * from ev_users where username = ?'
  sql.query(sqlapi, [body.username, body.password], (err, result) => {
    if (err) return res.cc('服務(wù)端錯(cuò)誤')
    // if (!result.length) return res.cc('用戶名/密碼錯(cuò)誤')
    // 調(diào)用bcrypt.compareSync判斷輸入密碼與數(shù)據(jù)庫加密密碼是否一致
    const compareResult = bcrypt.compareSync(body.password, result[0].password)
    if (!compareResult) return res.cc('登錄失?。?)
    const user = { ...result[0], password: '', user_pic: '' }
    // 對(duì)用戶的信息進(jìn)行加密,生成 Token 字符串
    const tokenStr = jwt.sign(user, config.jwtSecretKey, {
      expiresIn: config.expiresIn,
    })
    res.send({
      status: '200',
      data: 'ok',
      message: '登錄成功',
      token: 'Bearer ' + tokenStr,
    })
  })
})

3 . 最后貼出改造后的完整代碼,只貼注冊(cè)與登錄

const express = require('express')
const cors = require('cors')
// 導(dǎo)入 mysql 模塊
const mysql = require('mysql')

const axios = require('axios')

const app = express()

// 導(dǎo)入生成 Token 的包
const jwt = require('jsonwebtoken')
// 解析token
const expressJWT = require('express-jwt')

// 導(dǎo)入 bcryptjs 這個(gè)包
const bcrypt = require('bcryptjs')
// 建立與 MySQL 數(shù)據(jù)庫的連接關(guān)系
const sql = mysql.createPool({
  host: '127.0.0.1', // 數(shù)據(jù)庫的 IP 地址
  user: 'root', // 登錄數(shù)據(jù)庫的賬號(hào)
  password: 'root', // 登錄數(shù)據(jù)庫的密碼
  database: 'my_users', // 指定要操作哪個(gè)數(shù)據(jù)庫
})
axios.baserUrl = 'http://ihrm-java.itheima.net/'
// 處理跨域中間件
app.use(cors())
// 處理JSON表單格式中間件
app.use(express.json())
// 處理application/x-www-form-urlencoded表單格式的中間件
app.use(express.urlencoded({ extended: false }))

app.use(
  expressJWT({ secret: '服務(wù)端私有密匙(自己定義)', algorithms: ['HS256'] }).unless({
    path: [/^\/api||user/],
  })
)
// 錯(cuò)誤級(jí)別中間件
app.use((req, res, next) => {
  res.cc = function (err, status = 201) {
    res.send({
      status,
      data: '操作失敗',
      message: err,
    })
  }
  next()
})
// 定義錯(cuò)誤級(jí)別的中間件
app.use((err, req, res, next) => {
  console.log(err)
  // 身份認(rèn)證失敗后的錯(cuò)誤
  if (err.name === 'credentials_required') return res.cc('身份認(rèn)證失??!')
  // // 未知的錯(cuò)誤
  return res.send(err)
})
app.get('/get', (req, res) => {
  const body = req.query
  res.send({
    data: body,
  })
})

// 注冊(cè)接口
app.post('/user', (req, res) => {
  const body = req.body
  // 查詢數(shù)據(jù)庫 *(所有) 表單為 ev_users 里 所有username   ? 為占位符代表?xiàng)l件
  const query = 'select * from ev_users where username=?'
  // ()  第一位為sql
  sql.query(query, body.username, (err, result) => {
    // err 為執(zhí)行錯(cuò)誤信息    result為數(shù)據(jù)
    if (err)  return res.cc(err)
    // 判斷影響行數(shù)  能查詢到證明數(shù)據(jù)庫表單里存在這個(gè)值
    if (result.length > 0) return res.cc('用戶名已存在')
    // 調(diào)用 bcrypt.hashSync() 對(duì)密碼進(jìn)行加密  10代表鹽的長(zhǎng)度
    body.password = bcrypt.hashSync(body.password, 10)
    // 插入數(shù)據(jù)
    const sqlint = 'insert into ev_users set ?'

    sql.query(
      sqlint,
      { username: body.username, password: body.password },
      (err, result) => {
        if (err) return res.cc(err)
        if (!result.affectedRows) return res.cc('注冊(cè)失敗')
        res.send({
          status: 200,
          data: 'ok',
          message: '注冊(cè)成功',
        })
      }
    )
  })
})

// 登錄接口
app.post('/api', (req, res) => {
  const body = req.body
  // 查詢登錄用戶名/密碼數(shù)據(jù)庫是否存在,并匹配
  // let sqlapi = 'select * from ev_users where username = ? && password = ?'
  let sqlapi = 'select * from ev_users where username = ?'
  sql.query(sqlapi, [body.username, body.password], (err, result) => {
    if (err) return res.cc('服務(wù)端錯(cuò)誤')
    // if (!result.length) return res.cc('用戶名/密碼錯(cuò)誤')
    // 判斷密碼是否正確
    const compareResult = bcrypt.compareSync(body.password, result[0].password)
    if (!compareResult) return res.cc('登錄失??!')
    const user = { ...result[0], password: '', user_pic: '' }
    // 對(duì)用戶的信息進(jìn)行加密,生成 Token 字符串
    const tokenStr = jwt.sign(user, '服務(wù)端私有密匙(自己定義)', {
      expiresIn: '10h',
    })
    res.send({
      status: '200',
      data: 'ok',
      message: '登錄成功',
      token: 'Bearer ' + tokenStr,
    })
  })
})

// 啟動(dòng)服務(wù)器
app.listen(80, () => {
  console.log('express server running at http://127.0.0.1')
})

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容