token.js 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. 'use strict';
  2. const { CrudService } = require('naf-framework-mongoose-free/lib/service');
  3. const { BusinessError, ErrorCode } = require('naf-core').Error;
  4. const _ = require('lodash');
  5. const assert = require('assert');
  6. const { ObjectId } = require('mongoose').Types;
  7. //
  8. class TokenService extends CrudService {
  9. constructor(ctx) {
  10. super(ctx, 'token');
  11. this.redis = this.app.redis;
  12. this.tokenTimes = 2; // token的使用次数
  13. this.tokenTimeOut = 5 * 60; // x * 60s;token超时时间
  14. }
  15. /**
  16. * 生成token
  17. * token用于检测是否允许请求接口
  18. * 每个用户的每个token有使用次数(上面设置的),
  19. * @param {String} id 用户信息id
  20. * @property {String} oid 随机ObjectId作为key,在redis中也是使用这个作为key
  21. */
  22. async initToken(id) {
  23. // 生成混合id
  24. const oid = ObjectId().toString();
  25. const arr = [];
  26. // 将用户id翻转
  27. const idArr = _.reverse(oid.split(''));
  28. const oidArr = id.split('');
  29. // 将用户id和混合id进行穿插组合
  30. for (let i = 0; i < idArr.length; i++) {
  31. const v = idArr[i];
  32. const s = oidArr[i];
  33. arr.push(v, s);
  34. }
  35. // 拼接成要返回的token的键
  36. const tokenKey = arr.join('');
  37. // 设置该用户的token次数
  38. await this.redis.set(`token:${oid}`, this.tokenTimes, 'ex', this.tokenTimeOut);
  39. return tokenKey;
  40. }
  41. /**
  42. * 从token中取出用户id
  43. * @param {String} str token
  44. * @return {String} uid 用户id/oid redis的key
  45. */
  46. getIdFromToken(str) {
  47. const idArr = str.split('');
  48. const arr = [];
  49. const uArr = [];
  50. for (let i = 0; i < idArr.length; i += 2) {
  51. arr.push(idArr[i]);
  52. if (idArr[i + 1]) uArr.push(idArr[i + 1]);
  53. }
  54. const oid = _.reverse(arr).join('');
  55. const uid = uArr.join('');
  56. return { oid, uid };
  57. }
  58. /**
  59. * 检查并使用token
  60. * @param {String} token token
  61. */
  62. async useToken(token) {
  63. const { oid, uid } = this.getIdFromToken(token);
  64. let tvalue = await this.redis.get(`token:${oid}`);
  65. if (!(tvalue && parseInt(tvalue))) return { token, check: false };
  66. tvalue = parseInt(tvalue);
  67. if (tvalue - 1 <= 0) {
  68. // 把上个token删了
  69. await this.redis.del(`token:${oid}`);
  70. // 该token用完了,换下一个
  71. const newToken = await this.initToken(uid);
  72. return { token: newToken, check: true, fresh: true };
  73. }
  74. // token使用次数-1
  75. tvalue--;
  76. await this.redis.set(`token:${oid}`, tvalue);
  77. return { token, check: true };
  78. }
  79. }
  80. module.exports = TokenService;