UNPKG

egg-jianghu

Version:
207 lines (190 loc) 6.71 kB
'use strict'; // ========================================常用 require start=========================================== const Service = require('egg').Service; const { BizError, errorInfoEnum } = require('../constant/error'); const { tableEnum, userStatusEnum } = require('../constant/constant'); const validateUtil = require('../common/validateUtil'); const idGenerateUtil = require('../common/idGenerateUtil'); const geoip = require("geoip-lite"); // ========================================常用 require end============================================= const md5 = require("md5-node"); const actionDataaScheme = Object.freeze({ passwordLogin: { type: "object", additionalProperties: true, required: ["userId", "password", "deviceId"], properties: { userId: { type: "string", minLength: 3 }, password: { type: "string" }, deviceId: { type: "string" }, deviceType: { type: "string" }, needSetCookies: { anyOf: [{ type: "boolean" }, { type: "null" }] }, }, }, logout: { type: "object", additionalProperties: true, required: [], properties: { needSetCookies: { anyOf: [{ type: "boolean" }, { type: "null" }] }, }, }, resetPassword: { type: "object", additionalProperties: true, required: ["oldPassword", "newPassword"], properties: { oldPassword: { type: "string" }, newPassword: { type: "string" }, }, }, }); class UserService extends Service { async passwordLogin() { const app = this.app; const { jianghuKnex } = app; const { appId } = app.config; const { actionData } = this.ctx.request.body.appData; validateUtil.validate(actionDataaScheme.passwordLogin, actionData); const { userId, password, deviceType, deviceId, needSetCookies = true, } = actionData; const user = await jianghuKnex(tableEnum._view01_user) .where({ userId }) .first(); if (!user || !user.userId || user.userId !== userId) { throw new BizError(errorInfoEnum.user_not_exist); } const { userStatus } = user; if (userStatus !== userStatusEnum.active) { if (userStatus === userStatusEnum.banned) { throw new BizError(errorInfoEnum.user_banned); } throw new BizError(errorInfoEnum.user_status_error); } const passwordMd5 = md5(`${password}_${user.md5Salt}`); if (passwordMd5 !== user.password) { throw new BizError(errorInfoEnum.user_password_error); } const authToken = idGenerateUtil.uuid(36); // 存session 的目的是为了 // 1. 系统可以根据这个判断是否是自己生成的token // 2. 有时候系统升级需要 用户重新登陆/重新登陆,这时候可以通过清理旧session达到目的 const userSession = await jianghuKnex(tableEnum._user_session) .where({ userId, deviceId }) .first(); const userAgent = this.ctx.request.body.appData.userAgent || ""; const userIp = this.ctx.header["x-real-ip"] || this.ctx.request.ip || ""; const geo = geoip.lookup(userIp); let userIpRegion = ""; if (geo) { userIpRegion = `${geo.country}|${geo.region}|${geo.timezone}|${geo.city}|${geo.ll}|${geo.range}`; } if (userSession && userSession.id) { await jianghuKnex(tableEnum._user_session, this.ctx) .where({ id: userSession.id }) .jhUpdate({ authToken, deviceType, userAgent, userIp, userIpRegion }); } else { await jianghuKnex(tableEnum._user_session, this.ctx).jhInsert({ userId, deviceId, userAgent, userIp, userIpRegion, deviceType, authToken, }); } // 设置 cookies,用于 page 鉴权 if (needSetCookies) { this.ctx.cookies.set(`${appId}_authToken`, authToken, { httpOnly: false, signed: false, maxAge: 1000 * 60 * 60 * 24 * 1080, }); // 1080天 } return { authToken, deviceId, userId }; } async logout() { const { config: { appId }, jianghuKnex, } = this.app; const { userInfo } = this.ctx; const { actionData } = this.ctx.request.body.appData; validateUtil.validate(actionDataaScheme.logout, actionData); const { needSetCookies = true } = actionData; const { userId, deviceId } = userInfo.user; if (needSetCookies) { this.ctx.cookies.set(`${appId}_authToken`, null); } const user = await jianghuKnex(tableEnum._view01_user) .where({ userId }) .first(); if (!user || !userId) { throw new BizError({ ...errorInfoEnum.user_not_exist }); } const userSession = await jianghuKnex(tableEnum._user_session) .where({ userId, deviceId }) .first(); if (!userSession) { throw new BizError({ ...errorInfoEnum.request_token_invalid }); } await jianghuKnex(tableEnum._user_session, this.ctx) .where({ id: userSession.id }) .jhUpdate({ authToken: "" }); if (needSetCookies) { this.ctx.cookies.set(`${appId}_authToken`, null); } return {}; } async userInfo() { const { userInfo } = this.ctx; const { user } = userInfo; const { userId } = user; const { jianghuKnex } = this.app; if (userId) { userInfo.socketList = await jianghuKnex(tableEnum._user_session) .where({ userId, socketStatus: "online" }) .select("userId", "deviceId", "socketStatus"); } return userInfo; } async resetPassword() { const { actionData } = this.ctx.request.body.appData; validateUtil.validate(actionDataaScheme.resetPassword, actionData); const app = this.app; const { jianghuKnex } = app; const { oldPassword, newPassword } = actionData; const { userInfo: { user: { userId }, }, } = this.ctx; const user = await jianghuKnex(tableEnum._user).where({ userId }).first(); // 旧密码检查 const passwordMd5 = md5(`${oldPassword}_${user.md5Salt}`); if (passwordMd5 !== user.password) { throw new BizError(errorInfoEnum.user_password_reset_old_error); } // 密码一致检查 if (oldPassword === newPassword) { throw new BizError(errorInfoEnum.user_password_reset_same_error); } // 修改数据库中密码 const newMd5Salt = idGenerateUtil.uuid(12); const newPasswordMd5 = md5(`${newPassword}_${newMd5Salt}`); await jianghuKnex(tableEnum._user, this.ctx).where({ userId }).jhUpdate({ password: newPasswordMd5, clearTextPassword: newPassword, md5Salt: newMd5Salt, }); await jianghuKnex(tableEnum._user_session, this.ctx).where({ userId }).jhUpdate({ authToken: "" }) return {}; } } module.exports = UserService;