user.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  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.phoneLoginKey = 'phoneLogin:';
  20. this.conenctCode = '&&';
  21. }
  22. async beforeCreate(data) {
  23. const openid = _.get(data, 'openid');
  24. const phone = _.get(data, 'phone');
  25. if (!openid && phone) {
  26. const num = await this.model.count({ phone });
  27. if (num > 0) throw new BusinessError(ErrorCode.DATA_EXISTED, '该手机号已注册');
  28. } else if (openid) {
  29. const num = await this.model.count({ openid });
  30. if (num > 0) throw new BusinessError(ErrorCode.DATA_EXISTED, '该微信号已注册');
  31. }
  32. return data;
  33. }
  34. async resetPwd({ id }, { password }) {
  35. const data = await this.model.findById(id);
  36. if (!data) throw new BusinessError(ErrorCode.USER_NOT_EXIST);
  37. data.password = { secret: password };
  38. await data.save();
  39. }
  40. /**
  41. * 登陆
  42. * @param {Object} body 登陆参数
  43. * @param body.phone 账户
  44. * @param body.password 密码
  45. */
  46. async login({ phone, password }) {
  47. const { populate } = this.getRefMods();
  48. let user = await this.model.findOne({ phone }, '+password').populate(populate);
  49. if (!user) throw new BusinessError(ErrorCode.USER_NOT_EXIST);
  50. const { password: upwd, status } = user;
  51. if (status !== '0') throw new BusinessError(ErrorCode.USER_NOT_BIND, '该账号处于禁止使用状态');
  52. if (password !== upwd.secret) throw new BusinessError(ErrorCode.BAD_PASSWORD);
  53. // // 使用redis存储,后续的任何操作进行token的校验
  54. // await this.setUserInRedis(user);
  55. user = JSON.parse(JSON.stringify(user));
  56. delete user.password;
  57. delete user.meta;
  58. delete user.__v;
  59. const token = this.ctx.service.util.jwt.encrypt(user);
  60. return token;
  61. }
  62. /**
  63. * 微信登录
  64. * @param {Object} body 登陆参数
  65. * @param body.openid 微信小程序的openid
  66. */
  67. async wxLogin({ openid }) {
  68. const { populate } = this.getRefMods();
  69. const user = await this.model.findOne({ openid }).populate(populate);
  70. if (!user) throw new BusinessError(ErrorCode.USER_NOT_EXIST);
  71. const { status } = user;
  72. if (status !== '0') throw new BusinessError(ErrorCode.USER_NOT_BIND, '该账号处于禁止使用状态');
  73. delete user.meta;
  74. delete user.__v;
  75. const token = this.ctx.service.util.jwt.encrypt(user);
  76. return token;
  77. }
  78. /**
  79. * 绑定邮箱验证码
  80. * @param {Object} body 请求体
  81. * @param body.id 用户id
  82. * @param body.email 用户要绑定的邮箱
  83. */
  84. async toBindEmail({ id, email }) {
  85. const code = _.random(100000, 999999);
  86. const value = `${email}${this.conenctCode}${code}`;
  87. await this.redis.set(`${this.bindEmailKey}${id}`, value, 'EX', 300);
  88. // 发邮件
  89. const data = { config: this.emailServiceConfig, template: 'bindEmail', receiver: email, params: { code } };
  90. const url = `${this.emailServiceUrl}/sendEmail`;
  91. await this.httpUtil.cpost(url, data);
  92. }
  93. async checkBindEmail({ code, id, email }) {
  94. const redisData = await this.redis.get(`${this.bindEmailKey}${id}`);
  95. if (!redisData) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '验证码已超时');
  96. const arr = redisData.split(this.conenctCode);
  97. const rEmail = _.head(arr);
  98. const rCode = _.last(arr);
  99. if (code !== rCode) throw new BusinessError(ErrorCode.DATA_INVALID, '验证码错误');
  100. if (email !== rEmail) throw new BusinessError(ErrorCode.DATA_INVALID, '要绑定的邮箱与接收验证码的邮箱不是同一个邮箱');
  101. await this.model.updateOne({ _id: id }, { email });
  102. await this.redis.del(`${this.bindEmailKey}${id}`);
  103. }
  104. /**
  105. * 绑定手机验证码
  106. * @param {Object} body 请求体
  107. * @param body.id 用户id
  108. * @param body.phone 用户要绑定的手机
  109. */
  110. async toBindPhone({ id, phone }) {
  111. const num = await this.model.count({ phone });
  112. if (num > 0) throw new BusinessError(ErrorCode.DATA_EXISTED, '手机号已被绑定');
  113. const code = _.random(100000, 999999);
  114. const value = `${phone}${this.conenctCode}${code}`;
  115. await this.redis.set(`${this.bindPhoneKey}${id}`, value, 'EX', 300);
  116. // 发短信
  117. const data = { config: this.smsServiceConfig, template: 'bind', phone, params: { code } };
  118. const url = `${this.smsServiceUrl}/sendMessage`;
  119. await this.httpUtil.cpost(url, data);
  120. }
  121. async checkBindPhone({ code, id, phone }) {
  122. const redisData = await this.redis.get(`${this.bindPhoneKey}${id}`);
  123. if (!redisData) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '验证码已超时');
  124. const arr = redisData.split(this.conenctCode);
  125. const rphone = _.head(arr);
  126. const rCode = _.last(arr);
  127. if (code !== rCode) throw new BusinessError(ErrorCode.DATA_INVALID, '验证码错误');
  128. if (phone !== rphone) throw new BusinessError(ErrorCode.DATA_INVALID, '要绑定的手机号与接收验证码的手机号不是同一个手机号');
  129. await this.model.updateOne({ _id: id }, { phone });
  130. await this.redis.del(`${this.bindPhoneKey}${id}`);
  131. }
  132. // 发送登陆验证码
  133. async toLoginByCode({ phone }) {
  134. const code = _.random(100000, 999999);
  135. const value = `${phone}${this.conenctCode}${code}`;
  136. await this.redis.set(`${this.phoneLoginKey}${phone}`, value, 'EX', 300);
  137. // 发短信
  138. const data = { config: this.smsServiceConfig, template: 'login', phone, params: { code } };
  139. const url = `${this.smsServiceUrl}/sendMessage`;
  140. await this.httpUtil.cpost(url, data);
  141. }
  142. // 检查登陆验证码,然后登陆
  143. async checkLoginCode({ phone, code }) {
  144. const redisData = await this.redis.get(`${this.phoneLoginKey}${phone}`);
  145. if (!redisData) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '验证码已超时');
  146. const arr = redisData.split(this.conenctCode);
  147. const rphone = _.head(arr);
  148. const rCode = _.last(arr);
  149. if (code !== rCode) throw new BusinessError(ErrorCode.DATA_INVALID, '验证码错误');
  150. if (phone !== rphone) throw new BusinessError(ErrorCode.DATA_INVALID, '要登陆的手机号与接收验证码的手机号不是同一个手机号');
  151. const { populate } = this.getRefMods();
  152. const user = await this.model.findOne({ phone }).populate(populate);
  153. if (!user) throw new BusinessError(ErrorCode.USER_NOT_EXIST);
  154. const { status } = user;
  155. if (status !== '0') throw new BusinessError(ErrorCode.USER_NOT_BIND, '该账号处于禁止使用状态');
  156. delete user.meta;
  157. delete user.__v;
  158. const token = this.ctx.service.util.jwt.encrypt(user);
  159. return token;
  160. }
  161. /**
  162. * 删除用户
  163. * @param {Object} param 地址参数
  164. * @param {String} param.key 就是key
  165. * @param {String} param.target 操作对象
  166. */
  167. async delete({ key, target }) {
  168. const { opera_id, target: rt } = await this.ctx.service.util.user.getKeyData(key);
  169. const admin = _.get(this.ctx, 'admin');
  170. const _id = _.get(admin, '_id');
  171. if (opera_id !== _id) throw new BusinessError(ErrorCode.DATA_INVALID, '不是同一个操作人,操作无效');
  172. if (target !== rt) throw new BusinessError(ErrorCode.DATA_INVALID, '操作对象不是同一个数据,操作无效');
  173. await this.model.deleteOne({ _id: target });
  174. }
  175. async getUserIsLeader(id) {
  176. const user = await this.model.findById(id, { is_leader: 1 }).lean();
  177. if (!user) return false;
  178. const is_leader = _.get(user, 'is_leader', '1');
  179. return is_leader === '0';
  180. }
  181. async changeCacheToken() {
  182. const user_id = _.get(this.ctx, 'user._id');
  183. if (!user_id) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到用户信息');
  184. const user = await this.model.findById(user_id).lean();
  185. if (user) {
  186. delete user.meta;
  187. delete user.__v;
  188. if (!user.id) user.id = user_id;
  189. const token = this.ctx.service.util.jwt.encrypt(user);
  190. return token;
  191. }
  192. }
  193. }
  194. module.exports = UserService;