使用egg.js实现手机、验证码注册的项目实践
时间:2023-01-14 11:32:34|栏目:JavaScript代码|点击: 次
手机号注册、验证码校验
app/contrpoller/pass.js
'use strict'; const Controller = require('egg').Controller; class PassController extends Controller { //登录 async login() { await this.ctx.render('pass/login.html'); } async getCode(){ const { ctx,service } = this; const captcha=await service.tools.verify(); /* 获取服务里面返回的生成的验证码信息 */ this.ctx.session.identify_code=captcha.text; /* 验证码上面的信息,文字内容存放到session里面 */ ctx.response.type = 'image/svg+xml'; /* 返回的生成的验证码的格式 */ ctx.body=captcha.data; /* 给页面返回一张图片 */ } //注册第一步 输入手机号 async registerStep1() { await this.ctx.render('pass/register_step1.html'); } //注册第二步 验证码验证码是否正确 async registerStep2() { var sign=this.ctx.request.query.sign; var identify_code=this.ctx.request.query.identify_code; var add_day=await this.service.tools.getDay(); //年月日 var userTempResult=await this.ctx.model.User.UserTemp.find({"sign":sign,add_day:add_day}); if(userTempResult.length==0){ this.ctx.redirect('/register/registerStep1'); }else{ await this.ctx.render('pass/register_step2.html',{ sign:sign, phone:userTempResult[0].phone, identify_code:identify_code }); } } //注册第三步 输入密码 async registerStep3() { var sign = this.ctx.request.query.sign; var phone_code = this.ctx.request.query.phone_code; var msg = this.ctx.request.query.msg || ''; var add_day = await this.service.tools.getDay(); //年月日 var userTempResult = await this.ctx.model.User.UserTemp.find({ "sign": sign, add_day: add_day }); if (userTempResult.length == 0) { this.ctx.redirect('/register/registerStep1'); } else { await this.ctx.render('pass/register_step3.html', { sign: sign, phone_code: phone_code, msg: msg }); } } //完成注册 post async doRegister() { this.ctx.body='完成注册'; } //发送短信验证码 async sendCode(){ var phone=this.ctx.request.query.phone; var identify_code=this.ctx.request.query.identify_code; //用户输入的验证码 if(identify_code.toLowerCase()!=this.ctx.session.identify_code.toLowerCase()){ this.ctx.body={ success:false, msg:'输入的图形验证码不正确' } }else{ //判断手机格式是否合法 var reg =/^[\d]{11}$/; if(!reg.test(phone)){ this.ctx.body={ success:false, msg:'手机号不合法' } }else{ var add_day=await this.service.tools.getDay(); //年月日 var add_time=await this.service.tools.getTime(); var sign=await this.service.tools.md5(phone+add_day); //签名 var ip=this.ctx.request.ip.replace(/::ffff:/, ''); //获取客户端ip var phone_code=await this.service.tools.getRandomNum(); //发送短信的随机码 var userTempResult=await this.ctx.model.User.UserTemp.find({"sign":sign,add_day:add_day}); //1个ip 一天只能发10个手机号 var ipCount=await this.ctx.model.User.UserTemp.find({"ip":ip,add_day:add_day}).count(); if(userTempResult.length>0){ if(userTempResult[0].send_count<6 && ipCount<10){ //执行发送 var send_count=userTempResult[0].send_count+1; await this.ctx.model.User.UserTemp.updateOne({"_id":userTempResult[0]._id},{"send_count":send_count,'add_time':add_time}); this.ctx.session.phone_code=phone_code; //发送短信 this.service.sendmsg.send(phone,phone_code); console.log('---------------------------------'); console.log(phone_code,ipCount); this.ctx.body={ success:true, msg:'短信发送成功', sign:sign, } }else{ this.ctx.body={"success":false,msg:'当前手机号码发送次数达到上限,明天重试'}; } }else{ var userTmep=new this.ctx.model.User.UserTemp({ phone, add_day, sign, ip, send_count:1 }); userTmep.save(); this.ctx.session.phone_code=phone_code; //发送短信 this.service.sendmsg.send(phone,phone_code); this.ctx.body={ success:true, msg:'短信发送成功', sign:sign, } } } } } //验证验证码 async validatePhoneCode(){ var sign=this.ctx.request.query.sign; var phone_code=this.ctx.request.query.phone_code; var add_day=await this.service.tools.getDay(); //年月日 if(this.ctx.session.phone_code!=phone_code){ this.ctx.body={ success:false, msg:'您输入的手机验证码错误' } }else{ var userTempResult=await this.ctx.model.User.UserTemp.find({"sign":sign,add_day:add_day}); if(userTempResult.length<=0){ this.ctx.body={ success:false, msg:'参数错误' } }else{ //判断验证码是否超时 var nowTime=await this.service.tools.getTime(); if((userTempResult[0].add_time-nowTime)/1000/60>30){ this.ctx.body={ success:false, msg:'验证码已经过期' } }else{ //用户表有没有当前这个手机号 手机号有没有注册 var userResult=await this.ctx.model.User.User.find({"phone":userTempResult[0].phone}); if(userResult.length>0){ this.ctx.body={ success:false, msg:'此用户已经存在' } }else{ this.ctx.body={ success:true, msg:'验证码输入正确', sign:sign } } } } } } //完成注册 post async doRegister() { var sign=this.ctx.request.body.sign; var phone_code=this.ctx.request.body.phone_code; var add_day=await this.service.tools.getDay(); //年月日 var password=this.ctx.request.body.password; var rpassword=this.ctx.request.body.rpassword; var ip=this.ctx.request.ip.replace(/::ffff:/, '') ; if(this.ctx.session.phone_code!=phone_code){ //非法操作 this.ctx.redirect('/pass/registerStep1'); } var userTempResult=await this.ctx.model.User.UserTemp.find({"sign":sign,add_day:add_day}); if(userTempResult.length==0){ //非法操作 this.ctx.redirect('/pass/registerStep1'); }else{ //传入参数正确 执行增加操作 if(password.length<6 || password!=rpassword){ var msg='密码不能小于6位并且密码和确认密码必须一致'; this.ctx.redirect('/register/registerStep3?sign='+sign+'&phone_code='+phone_code+'&msg='+msg); }else{ var userModel=new this.ctx.model.User.User({ phone:userTempResult[0].phone, password:await this.service.tools.md5(password), last_ip:ip }); //保存用户 var userReuslt=await userModel.save(); if(userReuslt){ //跳转到登入页面 this.ctx.redirect('/login'); } // if(userReuslt){ // //获取用户信息 // var userinfo=await this.ctx.model.User.User.find({"phone":userTempResult[0].phone},'_id phone last_ip add_time email status'); // //用户注册成功以后默认登录 // //cookies 安全 加密 // this.service.cookies.set('userinfo',userinfo[0]); // this.ctx.redirect('/'); // } } } } } module.exports = PassController;
mode/user.js
module.exports = app => { const mongoose = app.mongoose; const Schema = mongoose.Schema; var d=new Date(); const User = new Schema({ /* ip:ip, password:password, phone:phone, add_time:add_time, last_ip:last_ip, status:status */ password:{type:String }, phone: {type:Number }, last_ip:{type:String }, add_time: { type:Number, default: d.getTime() }, email:{type:String }, status: { type:Number, default: 1 } }); return mongoose.model('User', User,'user'); };
router.js 路由配置
module.exports = app => { const { router, controller } = app; //普通用户登入 router.get('/user/verify', controller.admin.base.verify); //用户注册登录 router.get('/login',controller.default.pass.login); router.get('/register/registerStep1', controller.default.pass.registerStep1); router.get('/register/registerStep2', controller.default.pass.registerStep2); router.get('/register/registerStep3', controller.default.pass.registerStep3); //用户点击注册 router.get('/pass/sendCode', controller.default.pass.sendCode); //注册前台验证码 router.get('/verify', controller.default.pass.getCode); //注册验证手机短信码 router.get('/pass/validatePhoneCode', controller.default.pass.validatePhoneCode); //注册最后一步,输入账号和密码 router.post('/pass/doRegister', controller.default.pass.doRegister); };
service.js
获取验证码
'use strict'; //引入node.js 生成svg图形验证码模块 const svgCaptcha = require('svg-captcha'); const Service = require('egg').Service; const md5 = require('md5'); const path=require('path'); const sd = require('silly-datetime'); const mkdirp = require('mz-modules/mkdirp'); const Jimp = require("jimp"); //生成缩略图的模块 class ToolsService extends Service { async verify() { /* 生成验证码 */ const captcha = svgCaptcha.create( { size:4, //验证码图片里面的一些信息 fontSize: 50, width: 100, height:40, background: "#cc9966" }); return captcha; } /*生成随机的4位数字*/ async getRandomNum(){ let num=''; for(var i=0;i<4;i++){ num+=Math.floor(Math.random()*10) } return num; } /*生成当年当月当天的数字*/ async getDay(){ const day=sd.format(new Date(), 'YYYYMMDD'); return day; } /* 生成当前时间*/ async getTime(){ var date=new Date(); return date.getTime(); } async md5(string){ /* 封装一个md5加密*/ return md5(string); } async getFocusAddPath(filename){ /* 1: 获取传递过来的图片的名字, 获取当前日期 silly-datetime模块 2: 根据当前的日期,设置对应的文件夹,如果存在就不设置,不存在就设置 mz-modules模块 */ const day=sd.format(new Date(), 'YYYYMMDD'); let dir=path.join(this.config.uploadDir,day); await mkdirp(dir); const date=new Date(); let d=await date.getTime(); /*毫秒数*/ /*图片保存的路径*/ let uploadDir=path.join(dir,d+path.extname(filename)); /*app\public\admin\upload\20190614\1560520826971.png */ return { uploadDir:uploadDir, /* 保存到数据库的地址 */ saveDir:uploadDir.slice(3).replace(/\\/g,'/') } } //生成缩略图的公共方法 async jimpImg(target){ //上传图片成功以后生成缩略图 Jimp.read(target, (err, lenna) => { if (err) throw err; lenna.resize(200, 200) // resize .quality(90) // set JPEG quality .write(target+'_200*200'+path.extname(target)); // save lenna.resize(400, 400) // resize .quality(90) // set JPEG quality .write(target+'_400*400'+path.extname(target)); // save }); } } module.exports = ToolsService;
sendmsg.js
发送短信验证码
(需要上云片网购买短信服务)
'use strict'; const Service = require('egg').Service; var https = require('https'); var qs = require('querystring'); class SendmsgService extends Service { async send(mobile,code) { //apikey自己到云片网上面去买。 var apikey = '092******************eec'; // 修改为您要发送的手机号码,多个号码用逗号隔开 var mobile = mobile; // 修改为您要发送的短信内容 var text = '【java学习网】您的验证码是'+code; // 智能匹配模板发送https地址 var sms_host = 'sms.yunpian.com'; var send_sms_uri = '/v2/sms/single_send.json'; // 指定模板发送接口https地址 send_sms(send_sms_uri,apikey,mobile,text); function send_sms(uri,apikey,mobile,text){ var post_data = { 'apikey': apikey, 'mobile':mobile, 'text':text, };//这是需要提交的数据 var content = qs.stringify(post_data); post(uri,content,sms_host); } function post(uri,content,host){ var options = { hostname: host, port: 443, path: uri, method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' } }; var req = https.request(options, function (res) { // console.log('STATUS: ' + res.statusCode); // console.log('HEADERS: ' + JSON.stringify(res.headers)); res.setEncoding('utf8'); res.on('data', function (chunk) { console.log('BODY: ' + chunk); //如果错误 自己把它写入一个日志 }); }); //console.log(content); req.write(content); req.end(); } } } module.exports = SendmsgService;