'use strict'; const { CrudService } = require('naf-framework-mongoose-free/lib/service'); const { BusinessError, ErrorCode } = require('naf-core').Error; const _ = require('lodash'); const assert = require('assert'); const { ObjectId } = require('mongoose').Types; // class TokenService extends CrudService { constructor(ctx) { super(ctx, 'token'); this.redis = this.app.redis; this.tokenTimes = 2; // token的使用次数 this.tokenTimeOut = 5 * 60; // x * 60s;token超时时间 } /** * 生成token * token用于检测是否允许请求接口 * 每个用户的每个token有使用次数(上面设置的), * @param {String} id 用户信息id * @property {String} oid 随机ObjectId作为key,在redis中也是使用这个作为key */ async initToken(id) { // 生成混合id const oid = ObjectId().toString(); const arr = []; // 将用户id翻转 const idArr = _.reverse(oid.split('')); const oidArr = id.split(''); // 将用户id和混合id进行穿插组合 for (let i = 0; i < idArr.length; i++) { const v = idArr[i]; const s = oidArr[i]; arr.push(v, s); } // 拼接成要返回的token的键 const tokenKey = arr.join(''); // 设置该用户的token次数 await this.redis.set(`token:${oid}`, this.tokenTimes, 'ex', this.tokenTimeOut); return tokenKey; } /** * 从token中取出用户id * @param {String} str token * @return {String} uid 用户id/oid redis的key */ getIdFromToken(str) { const idArr = str.split(''); const arr = []; const uArr = []; for (let i = 0; i < idArr.length; i += 2) { arr.push(idArr[i]); if (idArr[i + 1]) uArr.push(idArr[i + 1]); } const oid = _.reverse(arr).join(''); const uid = uArr.join(''); return { oid, uid }; } /** * 检查并使用token * @param {String} token token */ async useToken(token) { const { oid, uid } = this.getIdFromToken(token); let tvalue = await this.redis.get(`token:${oid}`); if (!(tvalue && parseInt(tvalue))) return { token, check: false }; tvalue = parseInt(tvalue); if (tvalue - 1 <= 0) { // 把上个token删了 await this.redis.del(`token:${oid}`); // 该token用完了,换下一个 const newToken = await this.initToken(uid); return { token: newToken, check: true, fresh: true }; } // token使用次数-1 tvalue--; await this.redis.set(`token:${oid}`, tvalue); return { token, check: true }; } } module.exports = TokenService;