login.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. 'use strict';
  2. const assert = require('assert');
  3. const _ = require('lodash');
  4. const { ObjectId } = require('mongoose').Types;
  5. const { CrudService } = require('naf-framework-mongoose/lib/service');
  6. const { BusinessError, ErrorCode } = require('naf-core').Error;
  7. const jwt = require('jsonwebtoken');
  8. const uuid = require('uuid');
  9. class LoginService extends CrudService {
  10. constructor(ctx) {
  11. super(ctx, 'login');
  12. this.uModel = this.ctx.model.User;
  13. this.stuModel = this.ctx.model.Student;
  14. this.tModel = this.ctx.model.Teacher;
  15. this.schModel = this.ctx.model.School;
  16. this.hModel = this.ctx.model.Headteacher;
  17. }
  18. async login(data) {
  19. const { mobile, passwd, type } = data;
  20. assert(mobile, 'mobile不能为空');
  21. // assert(/^\d{11}$/i.test(mobile), 'mobile无效');
  22. assert(passwd, 'passwd不能为空');
  23. const res = await this.uModel.findOne({ mobile, type }, '+passwd');
  24. if (!res) {
  25. throw new BusinessError(ErrorCode.USER_NOT_EXIST);
  26. }
  27. // 验证密码
  28. // console.log('sjk-->' + res.passwd.secret);
  29. // console.log('sr-->' + passwd);
  30. if (res.passwd && res.passwd.secret !== passwd) {
  31. throw new BusinessError(ErrorCode.BAD_PASSWORD);
  32. }
  33. return await this.createJwt(res);
  34. }
  35. // 微信网页端登录(班主任,学生)
  36. async openidLogin(data) {
  37. const { openid, type } = data;
  38. const res = await this.uModel.findOne({ openid, type });
  39. if (!res) {
  40. throw new BusinessError(ErrorCode.USER_NOT_EXIST);
  41. }
  42. return await this.createJwt(res);
  43. }
  44. // 创建登录Token
  45. async createJwt({ _id, name, mobile, openid, type, uid, status }) {
  46. const { secret, expiresIn = '1d', issuer = type } = this.config.jwt;
  47. const subject = mobile;
  48. let _userid = '';
  49. let res = {};
  50. // 身份,0、中心管理元1、班主任用户2、学校用户3、教师4、学生
  51. if (type === '0') {
  52. _userid = _id.toString();
  53. res = { userid: _userid, name, type, id: _id, status };
  54. } else if (type === '1') {
  55. _userid = uid.toString();
  56. const result = await this.hModel.findById(_userid);
  57. res = { userid: _userid, name, type, id: _id, status };
  58. } else if (type === '2') {
  59. _userid = uid.toString();
  60. const result = await this.schModel.findById(_userid);
  61. if (!result) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到用户的角色信息');
  62. res = { userid: _userid, code: result.code, name, type, id: _id, status };
  63. } else if (type === '3') {
  64. _userid = uid.toString();
  65. const result = await this.tModel.findById(_userid);
  66. if (!result) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到用户的角色信息');
  67. res = { userid: _userid, schid: result.schid, schname: result.schname, name, subid: result.subid, type, id: _id, status };
  68. } else if (type === '4') {
  69. _userid = uid;
  70. // console.log('进入查询--' + _userid);
  71. const result = await this.stuModel.findById(_userid);
  72. if (!result) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到用户的角色信息');
  73. // console.log(result);
  74. res = {
  75. userid: _userid,
  76. schid: result.schid,
  77. schname: result.school_name,
  78. termid: result.termid,
  79. batchid: result.batchid,
  80. classid: result.classid,
  81. bedroomid: result.bedroomid,
  82. bedroom: result.bedroom,
  83. job: result.job,
  84. name,
  85. type,
  86. id: _id,
  87. status,
  88. planid: result.planid,
  89. };
  90. // console.warn(res);
  91. }
  92. const token = await jwt.sign(res, secret, { expiresIn, issuer, subject });
  93. return token;
  94. }
  95. // 微信校验mq接口
  96. async wxcheck(data) {
  97. const { qrcode, openid } = data;
  98. assert(qrcode, 'qrcode不能为空');
  99. assert(openid, 'openid不能为空');
  100. // TODO: 发布扫码成功消息
  101. const { mq } = this.ctx;
  102. const ex = 'qrcode.login';
  103. const parm = {
  104. durable: true,
  105. headers: {
  106. openid,
  107. },
  108. };
  109. if (mq) {
  110. await mq.topic(ex, qrcode, 'scaned', parm);
  111. }
  112. }
  113. // 微信登录接口
  114. async wxlogin(data) {
  115. const { qrcode, openid } = data;
  116. assert(qrcode, 'qrcode不能为空');
  117. assert(openid, 'openid不能为空');
  118. const res = await this.uModel.findOne({ openid });
  119. if (!res) {
  120. throw new BusinessError(ErrorCode.USER_NOT_EXIST);
  121. }
  122. const result = await this.createJwt(res);
  123. return result;
  124. }
  125. async userbind(data) {
  126. const { qrcode, openid } = data;
  127. assert(qrcode, 'qrcode不能为空');
  128. assert(openid, 'openid不能为空');
  129. const key = `naf:qrcode:login:${qrcode}`;
  130. const status = await this.app.redis.get(key);
  131. if (!status) {
  132. throw new BusinessError(ErrorCode.SERVICE_FAULT, '二维码已过期');
  133. }
  134. if (status !== 'pending') {
  135. throw new BusinessError(ErrorCode.SERVICE_FAULT, '二维码状态无效');
  136. }
  137. const res = await this.uModel.findOne({ openid });
  138. if (!res) {
  139. throw new BusinessError(ErrorCode.USER_NOT_EXIST);
  140. }
  141. const result = await this.createJwt(res);
  142. // TODO: 修改二维码状态,登录凭证保存到redis
  143. await this.app.redis.set(key, `scaned:${result}`, 'EX', 600);
  144. // TODO: 发布扫码成功消息
  145. const { mq } = this.ctx;
  146. const ex = 'qrcode.login';
  147. if (mq) {
  148. await mq.topic(ex, qrcode, 'scaned', { durable: true });
  149. }
  150. }
  151. /**
  152. * 创建二维码
  153. * 随机生成二维码,并保存在Redis中,状态初始为pending
  154. * 状态描述:
  155. * pending - 等待扫码
  156. * consumed - 使用二维码登录完成
  157. * ${jwt.token} - Jwt登录凭证
  158. */
  159. async createQrcode() {
  160. const qrcode = uuid();
  161. const key = `naf:qrcode:login:${qrcode}`;
  162. await this.app.redis.set(key, 'pending', 'EX', 600);
  163. return qrcode;
  164. }
  165. // 使用二维码换取登录凭证
  166. async qrcodeLogin(qrcode) {
  167. assert(qrcode, 'qrcode不能为空');
  168. const key = `naf:qrcode:login:${qrcode}`;
  169. const val = await this.app.redis.get(key);
  170. if (!val) {
  171. throw new BusinessError(ErrorCode.SERVICE_FAULT, '二维码已过期');
  172. }
  173. const [ status, token ] = val.split(':', 2);
  174. if (status !== 'scaned' || !token) {
  175. throw new BusinessError(ErrorCode.SERVICE_FAULT, '二维码状态无效');
  176. }
  177. // TODO: 修改二维码状态
  178. await this.app.redis.set(key, 'consumed', 'EX', 600);
  179. return { token };
  180. }
  181. // 检查二维码状态
  182. async checkQrcode(qrcode) {
  183. assert(qrcode, 'qrcode不能为空');
  184. const key = `naf:qrcode:login:${qrcode}`;
  185. const val = await this.app.redis.get(key);
  186. if (!val) {
  187. throw new BusinessError(ErrorCode.SERVICE_FAULT, '二维码已过期');
  188. }
  189. const [ status ] = val.split(':', 2);
  190. return { status };
  191. }
  192. }
  193. module.exports = LoginService;