'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'); // class UserService extends CrudService { constructor(ctx) { super(ctx, 'user'); this.redis = this.app.redis; this.model = this.ctx.model.User.User; this.bindEmailKey = 'bindEmail:'; this.httpUtil = this.ctx.service.util.httpUtil; this.emailServiceUrl = _.get(this.app, 'config.httpPrefix.email'); this.emailServiceConfig = _.get(this.app, 'config.emailConfig.config'); this.bindPhoneKey = 'bindPhone:'; this.smsServiceUrl = _.get(this.app, 'config.httpPrefix.sms'); this.smsServiceConfig = _.get(this.app, 'config.smsConfig.config'); this.conenctCode = '&&'; } async beforeCreate(data) { const openid = _.get(data, 'openid'); const phone = _.get(data, 'phone'); if (!openid && phone) { const num = await this.model.count({ phone }); if (num > 0) throw new BusinessError(ErrorCode.DATA_EXISTED, '该手机号已注册'); } else if (openid) { const num = await this.model.count({ openid }); if (num > 0) throw new BusinessError(ErrorCode.DATA_EXISTED, '该微信号已注册'); } return data; } async resetPwd({ id }, { password }) { const data = await this.model.findById(id); if (!data) throw new BusinessError(ErrorCode.USER_NOT_EXIST); data.password = { secret: password }; await data.save(); } /** * 登陆 * @param {Object} body 登陆参数 * @param body.phone 账户 * @param body.password 密码 */ async login({ phone, password }) { const { populate } = this.getRefMods(); let user = await this.model.findOne({ phone }, '+password').populate(populate); if (!user) throw new BusinessError(ErrorCode.USER_NOT_EXIST); const { password: upwd, status } = user; if (status !== '0') throw new BusinessError(ErrorCode.USER_NOT_BIND, '该账号处于禁止使用状态'); if (password !== upwd.secret) throw new BusinessError(ErrorCode.BAD_PASSWORD); // // 使用redis存储,后续的任何操作进行token的校验 // await this.setUserInRedis(user); user = JSON.parse(JSON.stringify(user)); delete user.password; delete user.meta; delete user.__v; const token = this.ctx.service.util.jwt.encrypt(user); return token; } /** * 微信登录 * @param {Object} body 登陆参数 * @param body.openid 微信小程序的openid */ async wxLogin({ openid }) { const { populate } = this.getRefMods(); const user = await this.model.findOne({ openid }).populate(populate); if (!user) throw new BusinessError(ErrorCode.USER_NOT_EXIST); const { status } = user; if (status !== '0') throw new BusinessError(ErrorCode.USER_NOT_BIND, '该账号处于禁止使用状态'); delete user.meta; delete user.__v; const token = this.ctx.service.util.jwt.encrypt(user); return token; } /** * 绑定邮箱验证码 * @param {Object} body 请求体 * @param body.id 用户id * @param body.email 用户要绑定的邮箱 */ async toBindEmail({ id, email }) { const code = _.random(100000, 999999); const value = `${email}${this.conenctCode}${code}`; await this.redis.set(`${this.bindEmailKey}${id}`, value, 'EX', 300); // 发邮件 const data = { config: this.emailServiceConfig, template: 'bindEmail', receiver: email, params: { code } }; const url = `${this.emailServiceUrl}/sendEmail`; await this.httpUtil.cpost(url, data); } async checkBindEmail({ code, id, email }) { const redisData = await this.redis.get(`${this.bindEmailKey}${id}`); if (!redisData) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '验证码已超时'); const arr = redisData.split(this.conenctCode); const rEmail = _.head(arr); const rCode = _.last(arr); if (code !== rCode) throw new BusinessError(ErrorCode.DATA_INVALID, '验证码错误'); if (email !== rEmail) throw new BusinessError(ErrorCode.DATA_INVALID, '要绑定的邮箱与接收验证码的邮箱不是同一个邮箱'); await this.model.updateOne({ _id: id }, { email }); await this.redis.del(`${this.bindEmailKey}${id}`); } /** * 绑定手机验证码 * @param {Object} body 请求体 * @param body.id 用户id * @param body.phone 用户要绑定的手机 */ async toBindPhone({ id, phone }) { const num = await this.model.count({ phone }); if (num > 0) throw new BusinessError(ErrorCode.DATA_EXISTED, '手机号已被绑定'); const code = _.random(100000, 999999); const value = `${phone}${this.conenctCode}${code}`; await this.redis.set(`${this.bindPhoneKey}${id}`, value, 'EX', 300); // 发短信 const data = { config: this.smsServiceConfig, template: 'bind', phone, params: { code } }; const url = `${this.smsServiceUrl}/sendMessage`; await this.httpUtil.cpost(url, data); } async checkBindPhone({ code, id, phone }) { const redisData = await this.redis.get(`${this.bindPhoneKey}${id}`); if (!redisData) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '验证码已超时'); const arr = redisData.split(this.conenctCode); const rphone = _.head(arr); const rCode = _.last(arr); if (code !== rCode) throw new BusinessError(ErrorCode.DATA_INVALID, '验证码错误'); if (phone !== rphone) throw new BusinessError(ErrorCode.DATA_INVALID, '要绑定的邮箱与接收验证码的邮箱不是同一个邮箱'); await this.model.updateOne({ _id: id }, { phone }); await this.redis.del(`${this.bindPhoneKey}${id}`); } } module.exports = UserService;