user.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  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. //
  7. class UserService extends CrudService {
  8. constructor(ctx) {
  9. super(ctx, 'user');
  10. this.redis = this.app.redis;
  11. this.model = this.ctx.model.User.User;
  12. this.bindEmailKey = 'bindEmail:';
  13. this.httpUtil = this.ctx.service.util.httpUtil;
  14. this.emailServiceUrl = _.get(this.app, 'config.httpPrefix.email');
  15. this.emailServiceConfig = _.get(this.app, 'config.emailConfig.config');
  16. this.bindPhoneKey = 'bindPhone:';
  17. this.smsServiceUrl = _.get(this.app, 'config.httpPrefix.sms');
  18. this.smsServiceConfig = _.get(this.app, 'config.smsConfig.config');
  19. this.conenctCode = '&&';
  20. }
  21. async beforeCreate(data) {
  22. const openid = _.get(data, 'openid');
  23. const phone = _.get(data, 'phone');
  24. if (!openid && phone) {
  25. const num = await this.model.count({ phone });
  26. if (num > 0) throw new BusinessError(ErrorCode.DATA_EXISTED, '该手机号已注册');
  27. } else if (openid) {
  28. const num = await this.model.count({ openid });
  29. if (num > 0) throw new BusinessError(ErrorCode.DATA_EXISTED, '该微信号已注册');
  30. }
  31. return data;
  32. }
  33. async resetPwd({ id }, { password }) {
  34. const data = await this.model.findById(id);
  35. if (!data) throw new BusinessError(ErrorCode.USER_NOT_EXIST);
  36. data.password = { secret: password };
  37. await data.save();
  38. }
  39. /**
  40. * 登陆
  41. * @param {Object} body 登陆参数
  42. * @param body.phone 账户
  43. * @param body.password 密码
  44. */
  45. async login({ phone, password }) {
  46. const { populate } = this.getRefMods();
  47. let user = await this.model.findOne({ phone }, '+password').populate(populate);
  48. if (!user) throw new BusinessError(ErrorCode.USER_NOT_EXIST);
  49. const { password: upwd, status } = user;
  50. if (status !== '0') throw new BusinessError(ErrorCode.USER_NOT_BIND, '该账号处于禁止使用状态');
  51. if (password !== upwd.secret) throw new BusinessError(ErrorCode.BAD_PASSWORD);
  52. // // 使用redis存储,后续的任何操作进行token的校验
  53. // await this.setUserInRedis(user);
  54. user = JSON.parse(JSON.stringify(user));
  55. delete user.password;
  56. delete user.meta;
  57. delete user.__v;
  58. const token = this.ctx.service.util.jwt.encrypt(user);
  59. return token;
  60. }
  61. /**
  62. * 微信登录
  63. * @param {Object} body 登陆参数
  64. * @param body.openid 微信小程序的openid
  65. */
  66. async wxLogin({ openid }) {
  67. const { populate } = this.getRefMods();
  68. const user = await this.model.findOne({ openid }).populate(populate);
  69. if (!user) throw new BusinessError(ErrorCode.USER_NOT_EXIST);
  70. const { status } = user;
  71. if (status !== '0') throw new BusinessError(ErrorCode.USER_NOT_BIND, '该账号处于禁止使用状态');
  72. delete user.meta;
  73. delete user.__v;
  74. const token = this.ctx.service.util.jwt.encrypt(user);
  75. return token;
  76. }
  77. /**
  78. * 绑定邮箱验证码
  79. * @param {Object} body 请求体
  80. * @param body.id 用户id
  81. * @param body.email 用户要绑定的邮箱
  82. */
  83. async toBindEmail({ id, email }) {
  84. const code = _.random(100000, 999999);
  85. const value = `${email}${this.conenctCode}${code}`;
  86. await this.redis.set(`${this.bindEmailKey}${id}`, value, 'EX', 300);
  87. // 发邮件
  88. const data = { config: this.emailServiceConfig, template: 'bindEmail', receiver: email, params: { code } };
  89. const url = `${this.emailServiceUrl}/sendEmail`;
  90. await this.httpUtil.cpost(url, data);
  91. }
  92. async checkBindEmail({ code, id, email }) {
  93. const redisData = await this.redis.get(`${this.bindEmailKey}${id}`);
  94. if (!redisData) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '验证码已超时');
  95. const arr = redisData.split(this.conenctCode);
  96. const rEmail = _.head(arr);
  97. const rCode = _.last(arr);
  98. if (code !== rCode) throw new BusinessError(ErrorCode.DATA_INVALID, '验证码错误');
  99. if (email !== rEmail) throw new BusinessError(ErrorCode.DATA_INVALID, '要绑定的邮箱与接收验证码的邮箱不是同一个邮箱');
  100. await this.model.updateOne({ _id: id }, { email });
  101. await this.redis.del(`${this.bindEmailKey}${id}`);
  102. }
  103. /**
  104. * 绑定手机验证码
  105. * @param {Object} body 请求体
  106. * @param body.id 用户id
  107. * @param body.phone 用户要绑定的手机
  108. */
  109. async toBindPhone({ id, phone }) {
  110. const code = _.random(100000, 999999);
  111. const value = `${phone}${this.conenctCode}${code}`;
  112. await this.redis.set(`${this.bindPhoneKey}${id}`, value, 'EX', 300);
  113. // 发短信
  114. const data = { config: this.smsServiceConfig, template: 'bind', phone, params: { code } };
  115. const url = `${this.smsServiceUrl}/sendEmail`;
  116. await this.httpUtil.cpost(url, data);
  117. }
  118. }
  119. module.exports = UserService;