[記錄三]Vue+node+koa2+mysql+nginx+redis,全棧開發小程序和(hé / huò)管理員管理 - 新聞資訊 - 雲南小程序開發|雲南軟件開發|雲南網站建設-昆明融晨信息技術有限公司

159-8711-8523

雲南網建設/小程序開發/軟件開發

知識

不(bù)管是(shì)網站,軟件還是(shì)小程序,都要(yào / yāo)直接或間接能爲(wéi / wèi)您産生價值,我們在(zài)追求其視覺表現的(de)同時(shí),更側重于(yú)功能的(de)便捷,營銷的(de)便利,運營的(de)高效,讓網站成爲(wéi / wèi)營銷工具,讓軟件能切實提升企業内部管理水平和(hé / huò)效率。優秀的(de)程序爲(wéi / wèi)後期升級提供便捷的(de)支持!

您當前位置>首頁 » 新聞資訊 » 小程序相關 >

[記錄三]Vue+node+koa2+mysql+nginx+redis,全棧開發小程序和(hé / huò)管理員管理

發表時(shí)間:2020-9-21

發布人(rén):融晨科技

浏覽次數:53

項目中凡是(shì)涉及到(dào)用戶登錄注冊的(de)都需要(yào / yāo)一個(gè)登錄态來(lái)驗證用戶的(de)登錄狀态,常用的(de)登錄台無外乎是(shì)token、session啊這(zhè)些标識。這(zhè)裏我使用的(de)是(shì)token字段。token一般會包含用戶的(de)個(gè)人(rén)信息,如:賬号、賬号id、用戶名等等,更爲(wéi / wèi)安全的(de)是(shì)加入一個(gè)自定義的(de)鹽(salt)一起加密,防止用戶信息洩漏。下面就(jiù)一起來(lái)使用一下:

說(shuō)到(dào)token,肯定會想到(dào)後端是(shì)怎麽知道(dào)前端給我的(de)token是(shì)不(bù)是(shì)我傳給他(tā)的(de)有效值呢?就(jiù)是(shì)說(shuō)後端需要(yào / yāo)有個(gè)值去跟前端傳過來(lái)的(de)token進行比較才知道(dào)合法性。所以(yǐ)後端在(zài)生成token的(de)同時(shí)自己也(yě)需要(yào / yāo)将這(zhè)個(gè)生成的(de)token存下來(lái)備用。我這(zhè)裏選用的(de)redis。它是(shì)一個(gè)數據庫,以(yǐ)鍵值對的(de)形式存儲,這(zhè)樣我就(jiù)可以(yǐ)将生成的(de)token存儲下來(lái)了(le/liǎo)。至于(yú)redis的(de)安裝和(hé / huò)部署這(zhè)裏就(jiù)不(bù)累贅了(le/liǎo),這(zhè)裏直接将使用。
在(zài)項目根目錄下新建一個(gè)redis文件夾。其下新建一個(gè)redis.js文件。

//redis.js
const Redis = require('ioredis')//導入模塊
const redis = {
    port: 6379,          // Redis port
    host: '127.0.0.1',   // Redis host
    prefix: '***', //存諸前綴
    ttl: 60 * 60 * 24 * 7 * 1000,  //過期時(shí)間   
    family: 4,
    db: 0
}
const redisClient = new Redis(redis)
//導出(chū)備用
module.exports = redisClient

這(zhè)樣redis就(jiù)可以(yǐ)使用了(le/liǎo)。

本文使用jsonwebtoken進行加密和(hé / huò)解密。
因爲(wéi / wèi)加密和(hé / huò)解密是(shì)很多接口都需要(yào / yāo)用的(de)東西,所以(yǐ)我将這(zhè)些方法寫到(dào)公共的(de)部分去。
utils文件下建一個(gè)common.js,用來(lái)存放公共的(de)方法。

//common.js
const secret = require('./secret')//導入自定義的(de)鹽
const jwt = require('jsonwebtoken')//導入jsonwebtoken
const verify = util.promisify(jwt.verify) // token解密
const common = {//定義一個(gè)對象
  //加密
  //後端生成唯一的(de)key
  /*
  * paylod:包含來(lái)用戶的(de)信息
  * secret.secret 自定義的(de)鹽(salt)
  * expiresIn 設置這(zhè)個(gè)token的(de)有效期
  */
  //jwt.sign是(shì)jsonwebtoken模塊的(de)一個(gè)方法,可以(yǐ)将傳入的(de)信息加密
  getToken(paylod, expiresIn) {
    return jwt.sign(paylod, secret.secret, expiresIn)
  },
  //解密
  //根據收到(dào)的(de)token獲取用戶信息
  getUserInfo(token) {
    return verify(token, secret.secret) 
  },
}
//導出(chū)這(zhè)個(gè)對象給外部使用
module.exports=common

新建一個(gè)secret.js文件用來(lái)存放自定義的(de)信息

在(zài)這(zhè)裏插入圖片描述
?? 這(zhè)裏建議鹽最好亂寫 寫得越亂越好,各種字符都加上(shàng),并亂序寫。

加密

我們在(zài)用戶登錄成功的(de)時(shí)候将用戶信息加密。所以(yǐ)我在(zài)我的(de)管理員登錄接口那寫。

我的(de)在(zài)routes文件下的(de)admin.js文件

//admin.js
const router = require('koa-router')()
const api = require('../controllers/api')
const redisClient = require('../redis/redis.js')
const common = require('../util/comon')

router.prefix('/admin')
//管理員登錄
router.post('/userLogin', async (ctx, next) => {
	/*寫你的(de)接口邏輯*/
	//定義一個(gè)用戶信息對象
	const paylod = {
        name: '登錄用戶的(de)用戶名',
        userid: '登錄用戶的(de)id',//登錄時(shí)可查表查拿到(dào)用戶id
        author: '13414851033@163.com',
        type:'***',
        timestamp: new Date()//加個(gè)時(shí)間戳保證加密後token的(de)唯一性
    }
    
    /*核心代碼*/
    
    // 調用上(shàng)面公共的(de)token加密方法(注:這(zhè)裏是(shì)沒有傳鹽進去的(de),我是(shì)直接在(zài)common文件引入來(lái)鹽)
    // expiresIn設置token的(de)有效期是(shì)7天
    const token = await common.getToken(paylod, { expiresIn: '7 days' })
    //每次登錄之(zhī)前先清除掉所有的(de)有關此用戶的(de)key(根據用戶id)
    let preToken = await redisClient.get(result.userid)
    //這(zhè)個(gè)preToken就(jiù)是(shì)當初登錄時(shí)redis存下來(lái)的(de)key
    await redisClient.del(preToken)
    //用token作爲(wéi / wèi)key、自定義的(de)token前綴+token作爲(wéi / wèi)值 傳key給前端作爲(wéi / wèi)校驗
    await redisClient.set(token, secret.identif + token)
    //再生成一對鍵值對 用來(lái)記錄是(shì)屬于(yú)哪個(gè)用戶的(de)token 用戶id作爲(wéi / wèi)key 傳給前端的(de)token(上(shàng)一條鍵值對的(de)key)作爲(wéi / wèi)值
    await redisClient.set(result.userid,token)
    ctx.body = {
        status: 200,
        code: 200,
        message: '登錄成功',
        data: result,
        token: token//将token傳給前端
    }
}

這(zhè)樣登錄成功後的(de)話前端就(jiù)能收到(dào)後端生成的(de)唯一性的(de)token了(le/liǎo),同時(shí)我也(yě)生成了(le/liǎo)兩對的(de)鍵值對。一對是(shì)以(yǐ)token爲(wéi / wèi)key,以(yǐ)自定義的(de)token前綴爲(wéi / wèi)value;一對是(shì)以(yǐ)用戶id爲(wéi / wèi)key,以(yǐ)token作爲(wéi / wèi)值的(de)數據。在(zài)用戶登錄時(shí)拿到(dào)用戶的(de)id,在(zài)redis中清除掉以(yǐ)這(zhè)個(gè)用戶id爲(wéi / wèi)key的(de)記錄,再存入一條以(yǐ)token爲(wéi / wèi)key的(de)記錄。這(zhè)樣就(jiù)能保證每次用戶登錄該用戶都是(shì)隻有一個(gè)合法的(de)key(就(jiù)是(shì)所謂的(de)同一個(gè)賬戶在(zài)多地(dì / de)登錄會擠掉其他(tā)人(rén)的(de)登錄狀态)。

解密

加密完之(zhī)後客戶端請求必然需要(yào / yāo)帶上(shàng)登錄态token來(lái)操作數據,但是(shì)不(bù)可能在(zài)客戶端去傳用戶的(de)數據,那樣太不(bù)安全了(le/liǎo),這(zhè)樣我上(shàng)面生成token時(shí)将用戶信息加進去的(de)數據就(jiù)有用處了(le/liǎo),隻要(yào / yāo)解密我就(jiù)能知道(dào)這(zhè)個(gè)token所攜帶的(de)用戶信息了(le/liǎo)。這(zhè)個(gè)token客戶端看到(dào)也(yě)是(shì)不(bù)知道(dào)用戶信息的(de),所以(yǐ)相對來(lái)說(shuō)比較安全些。

在(zài)common.js寫了(le/liǎo)一個(gè)獲取前端傳入的(de)token(走請求頭傳入,不(bù)以(yǐ)參數的(de)形式)

//common.js
 //根據請求頭的(de)信息獲取前端傳入的(de)token
 getHeaderToken(ctx) { 
   if (ctx.header && ctx.header.token) { 
     return ctx.header.token
   }
 }
const common = require('../util/comon')
//删除管理員
router.post('/****', async (ctx, next) => {
	let token = await common.getHeaderToken(ctx)
	let userInfo = await common.getUserInfo(token)
	//用戶名
	console.log(userInfo.name)
	//用戶id
	console.log(userInfo.userid)
}

所以(yǐ),隻要(yào / yāo)前端傳入token,後端就(jiù)能知道(dào)這(zhè)個(gè)token所攜帶的(de)用戶的(de)信息,方便後端處理數據所需的(de)必備條件。

以(yǐ)上(shàng)就(jiù)是(shì)本文介紹token的(de)使用,下文将介紹根據token登錄态控制接口請求權限。

上(shàng)一篇:編寫接口路由
下一篇:token控制接口權限

相關案例查看更多