const userModel = require('../model/user'); const jwt = require('jsonwebtoken'); const bcrypt = require('bcrypt'); const secret = require('../config/secret'); const Response = require('../util/response'); const aliClient = require('../util/aliClient'); const getTokenUser = require('../util/tokenProcessor'); class UserController { /** * 登录 * @param ctx * @returns {Promise.} */ static async login(ctx) { const data = ctx.request.body; const user = await userModel.findByPhone(data.phone); if (user) { const confirmRes = bcrypt.compareSync(data.password, user.password); if(!confirmRes){ ctx.body = Response.failed('密码错误,请重试') }else if(!user.isValid){ ctx.body = Response.failed('账号封禁中') }else{ // console.log('ctx',ctx); // console.log('ctx.cookies.redirect_uri',ctx.cookies.get('redirect_uri')); let redirect_uri = ctx.cookies.get('redirect_uri'); let client_id = ctx.cookies.get('client_id'); if(!redirect_uri){ redirect_uri = ctx.origin+"/api/receiveIDToken"; } if(!client_id){ client_id = 'seec-portal'; } let data = { iss : 'p.seecoder.cn', sub: user.phone, aud: client_id, auth_time: Math.floor(new Date().getTime() / 1000), iat: Math.floor(new Date().getTime() / 1000), exp: Math.floor(new Date().getTime() / 1000 + 24 * 60 * 60), user_info: {phone: user.phone, email: user.email, id: user.id, name: user.name ,role: user.role} }; const token = jwt.sign(data, secret.sign); //ctx.redirect(redirect_uri + "?id_token=" + token); ctx.cookies.set('redirect_uri', '', { maxAge:0 }); ctx.cookies.set('client_id', '', { maxAge:0 }); ctx.body = Response.success({token: token, name: user.name, path:redirect_uri}); } } else { ctx.body = Response.failed('此账号不存在'); } } static canManageUser(ctx){ let curUser = getTokenUser(ctx); if (curUser === null){// 没有身份,不可以 return false; } // 管理员或者老师可以管理 return curUser.role === "ADMIN" || curUser.role === "TEACHER"; } static async batchResetPassword(ctx){ if (!UserController.canManageUser(ctx)){ return "Method Not Allowed." } else{ let data=ctx.request.body; const promiseList = data.map(async item => { const hashPassword = bcrypt.hashSync(item.password, 10); return await userModel.resetPassword(item.phone,hashPassword); }) const resList = await Promise.all(promiseList) let result=new Array(); for(let i=0;i} */ static async register(ctx) { const { name, password, phone, email, identifyCode } = ctx.request.body; let curUser = null; try{ curUser = await getTokenUser(ctx); }catch (e){ console.log('接收到用户创建请求') } try { console.log(ctx.request.body) console.log(identifyCode) if (curUser === null || curUser.role === "STUDENT"){ // 普通用户注册流程 UserController.validateIdentifyCode(ctx,identifyCode,phone) //需要验证手机验证码 ctx.session.verification_phone = undefined; ctx.session.verification_code = undefined; } const result = await UserController.createUser(name, password, phone, email) ctx.body = Response.success({name:result.data.name}) }catch (e) { ctx.body = Response.failed(e.message) } } //创建用户 static async createUser(name, password, phone, email){ UserController.validateRegistrationData(name, password, phone, email); //注册逻辑 const hashPassword = bcrypt.hashSync(password, 10); const result = await userModel.create(name, hashPassword, phone, email); if (result.code === 0) { return result //返回创建成功的对象 } else if (result.code === -2) { throw new Error('此手机号已注册'); } else if (result.code === -1) { throw new Error('此用户名已使用'); }else { throw new Error("未知错误") } } static validateIdentifyCode(ctx,identifyCode,phone){ if (!ctx.session.verification_phone || !ctx.session.verification_code) { throw new Error('请重新获取验证码') } if (ctx.session.verification_code !== identifyCode || ctx.session.verification_phone !== phone) { throw new Error('验证码错误'); } console.log('验证成功',ctx.session.verification_code,ctx.session.verification_phone) } // 验证注册数据是否合法 static validateRegistrationData(name, password, phone, email) { const emailRegex = /^[a-zA-Z0-9_-]+@([a-zA-Z0-9_-]+\.)*[a-zA-Z0-9_-]+\.(com|cn|net|org)$/; const nameRegex = /^[\u4e00-\u9fa5a-zA-Z0-9_]+$/; //由中文、字母、数字、下划线组成且不包含其他字符的字符串 if (!emailRegex.test(email)) { throw new Error('邮箱格式有误'); } if (name.length < 1 || name.length > 16) { throw new Error('姓名长度应在1到16之间'); } if (password.length < 6 || password.length > 20) { throw new Error('密码长度应在6到20之间'); } if (phone.length !== 11) { throw new Error('手机号码长度应为11位'); } if (!nameRegex.test(name)) { throw new Error('用户名只能包含中文、字母、数字和下划线'); } } static async sendMessage(ctx){ let {phone} = ctx.request.body; let code = ""; for(let i = 0; i < 6; i++){ code+=Math.floor(Math.random()*10) } let params = { PhoneNumbers: phone, SignName: 'SEECODER', TemplateCode: 'SMS_253920073', TemplateParam: '{"code":"' + code + '"}' }; let options = { timeout: 3000, // default 3000 ms formatAction: true, // default true, format the action to Action formatParams: true, // default true, format the parameter name to first letter upper case method: 'GET', // set the http method, default is GET headers: {}, // set the http request headers }; try{ const result = await aliClient.request('SendSms', params); // console.log("result:", result); if(result.Code === "OK"){ ctx.session.maxAge = 5 * 60 * 1000; ctx.session.verification_code = code; ctx.session.verification_phone = phone; console.log('verification_code:', ctx.session.verification_code); ctx.body = Response.success({message: '发送成功'}); }else{ console.log("error:", result.message); ctx.body = Response.failed("发送失败,请重试"); } }catch (e) { console.log(e); ctx.body = Response.failed("发送失败,请重试"); } } static async getInfo(ctx) { let theUser = await getTokenUser(ctx); if(!theUser){ ctx.status = 401; }else{ let id = theUser.id; const user = await userModel.findByUid(id); if (user) { ctx.body = Response.success({phone: user.phone, email: user.email, id: user.id, name: user.name, signature: user.signature}); } else { ctx.body = Response.failed('用户信息获取失败'); } } } static async saveName(ctx){ let theUser = await getTokenUser(ctx); if(!theUser){ ctx.status = 401; }else{ let id = theUser.id; let newName = ctx.request.body.newName; let result = await userModel.updateName(id, newName); if(result.code === 0){ ctx.body = Response.success({}); }else{ ctx.body = Response.failed('此昵称已被占用'); } } } static async saveEmail(ctx){ let theUser = await getTokenUser(ctx); if(!theUser){ ctx.status = 401; }else{ let id = theUser.id; let newEmail = ctx.request.body.newEmail; const myReg=/^[a-zA-Z0-9_-]+@([a-zA-Z0-9]+\.)+(com|cn|net|org)$/; if(!myReg.test(newEmail)){ ctx.body = Response.failed('邮箱格式有误'); }else{ let result = await userModel.updateEmail(id, newEmail); if(result.code === 0){ ctx.body = Response.success({}); }else{ ctx.body = Response.failed('修改失败'); } } } } static async saveSignature(ctx){ let theUser = await getTokenUser(ctx); if(!theUser){ ctx.status = 401; }else{ let id = theUser.id; let newSignature = ctx.request.body.newSignature; if(newSignature === 0){ ctx.body = Response.failed('个性签名不得为空'); }else if(newSignature > 20){ ctx.body = Response.failed('个性签名过长'); }else { let result = await userModel.updateSignature(id, newSignature); if(result.code === 0){ ctx.body = Response.success({}); }else{ ctx.body = Response.failed('修改失败'); } } } } static async resetPassword(ctx) { const data = ctx.request.body; if(!ctx.session.verification_phone || !ctx.session.verification_code){ ctx.body = Response.failed('请重新获取验证码'); }else if(ctx.session.verification_code !== data.identifyCode || ctx.session.verification_phone !== data.phone){ ctx.body = Response.failed('验证码错误'); }else if( data.password.length<6 || data.password.length>20 || data.phone.length !== 11){ ctx.body = Response.failed('参数非法'); }else{ const hashPassword = bcrypt.hashSync(data.password, 10); const result = await userModel.resetPassword(data.phone, hashPassword); ctx.session.verification_phone = undefined; ctx.session.verification_code = undefined; if (result) { ctx.body = Response.success({}); } else { ctx.body = Response.failed('此手机号未注册'); } } } } module.exports = UserController;