zoukankan      html  css  js  c++  java
  • koa+nodemailer实现邮箱验证注册功能

    一、辅助代码

    在server/dbs/config.js里定义redis、smtp等相关配置:

    module.exports = {
      dbs: 'mongodb://127.0.0.1:27017/student',
      redis: {
        get host() {
          return '127.0.0.1'
        },
        get port() {
          return 6379
        }
      },
      smtp: {
        get host() {
          return 'smtp.qq.com'
        },
        get user() {
          return 'xxxx@qq.com'
        },
        get pass() {
          return 'xxxxxxxxxxxxx'
        },
        get code() {
          return () => {
            return Math.random().toString(16).slice(2, 6).toUpperCase()
          }
        },
        get expire() {
          return () => {
            return new Date().getTime() + 60 * 1000
          }
        }
      }
    }
    
    

    在server/dbs/models/users.js定义User表,用来存储用户信息:

    const mongoose = require('mongoose');
    //定义一个描述表结构的Schema
    let userSchema = new mongoose.Schema({
      username: {
        type: String,
        unique: true,
        require: true
      },
      password: {
        type: String,
        require: true
      },
      email: {
        type: String,
        require: true
      }
    })
    //把这个 schema 编译成一个 Model,和表联系起来,model 是我们构造 document 的 Class
    module.exports = mongoose.model('User', userSchema)
    

    在入口文件server/index.js里做连接数据库、配置路由等工作

    const Koa = require('koa')
    const { Nuxt, Builder } = require('nuxt')
    const mongoose = require('mongoose')
    const consola = require('consola')
    const config = require('../nuxt.config.js')
    const dbConfig = require('./dbs/config')
    const json = require('koa-json')
    const bodyParser = require('koa-bodyparser')
    const users = require('./interface/users')
    const app = new Koa()
    config.dev = app.env !== 'production'
    //koa-bodyparser:处理程序之前,在中间件中对传入的请求体进行解析
    app.use(bodyParser({
      extendTypes: ['json', 'form', 'text']
    }))
    //koa-json:让 Koa2 支持响应 JSON 数据
    app.use(json())
    //连接数据库
    mongoose.connect(dbConfig.dbs, {
      useNewUrlParser: true
    })
    async function start() {
      // Instantiate nuxt.js
      const nuxt = new Nuxt(config)
    
      const {
        host = process.env.HOST || '127.0.0.1',
        port = process.env.PORT || 3000
      } = nuxt.options.server
    
      // Build in development
      if (config.dev) {
        const builder = new Builder(nuxt)
        await builder.build()
      } else {
        await nuxt.ready()
      }
      app.use(users.routes(), users.allowedMethods())
      app.use((ctx) => {
        ctx.status = 200
        ctx.respond = false // Bypass Koa's built-in response handling
        ctx.req.ctx = ctx // This might be useful later on, e.g. in nuxtServerInit or with nuxt-stash
        nuxt.render(ctx.req, ctx.res)
      })
    
      app.listen(port, host)
      consola.ready({
        message: `Server listening on http://${host}:${port}`,
        badge: true
      })
    }
    
    start()
    

    二、核心代码

    在server/interface/users.js里定义接口:

    const Router = require('koa-router')
    const Redis = require('koa-redis')
    const nodemailer = require('nodemailer')
    const User = require('../dbs/models/users')
    const Email = require('../dbs/config')
    //新建router实例
    let router = new Router({
      prefix: '/users'
    })
    //新建redis客户端
    const Store = new Redis().client
    // signup 注册接口实现
    router.post('/signup', async (ctx, next) => {
      const { code, username, password, email } = ctx.request.body
      //校验code
      if (code) {
        const saveCode = await Store.hget(`nodemail:${username}`, 'code')
        const saveExpire = await Store.hget(`nodemail:${username}`, 'expire')
        if (code === saveCode) {
          if (new Date().getTime() - saveExpire > 0) {
            ctx.body = {
              code: -1,
              msg: '验证码已过期,请重新尝试'
            }
            return false
          }
        } else {
          ctx.body = {
            code: -1,
            msg: '请填写正确的验证码'
          }
          return false
        }
      } else {
        ctx.body = {
          code: -1,
          msg: '请填写验证码'
        }
        return false
      }
      //校验 username是否已经存在数据库
      const name = await User.find({ username })
      if (name.length) {
        ctx.body = {
          code: -1,
          msg: '用户名已存在'
        }
        return
      }
      // 把注册信息username、password、email存数据库
      const user = await User.create({username, password, email})
      try {
        user.save()
        ctx.body = {
          code: 0,
          msg: '注册成功',
        }
        return
      } catch (e) {
        ctx.body = {
          code: -1,
          msg: '服务端错误'
        }
        return
      }
    })
    //verify 发送验证码接口实现
    router.post('/verify', async (ctx, next) => {
      //校验是不是一分钟之内
      let username = ctx.request.body.username;
      let email = ctx.request.body.email;
      const saveExpire = await Store.hget(`nodemail:${username}`, 'expire');
      if (saveExpire && new Date().getTime() - saveExpire < 0) {
        ctx.body = {
          code: -1,
          msg: '验证请求过于频繁,1分钟内1次'
        }
        return false
      }
      //发送端信息
      let transporter = nodemailer.createTransport({
        service: 'qq', 
        port: 465, // SMTP 端口
        secureConnection: true, // 使用了 SSL
        auth: {
          user: Email.smtp.user,
          pass: Email.smtp.pass
        }
      });
      //接受端信息
      let ko = {
        code: Email.smtp.code(),
        expire: Email.smtp.expire(),
        email,
        user: username
      }
      //邮件信息
      let mailOptions = {
        from: `《李赵测试网站》<${Email.smtp.user}>`,
        to: ko.email,
        subject: '李赵测试网站验证码',
        html: `${ko.user}您好,您正在《李赵测试网站》注册,验证码是:${ko.code}`
      };
      //发送邮件
      transporter.sendMail(mailOptions, (error, info) => {
        if (error) {
          return console.log(error);
        } else {
          Store.hmset(`nodemail:${ko.user}`, 'code', ko.code)
          Store.hmset(`nodemail:${ko.user}`, 'expire', ko.expire)
          Store.hmset(`nodemail:${ko.user}`, 'email', ko.email)
        }
      });
      //ctx返回值
      ctx.body = {
        code: 0,
        msg: '验证码发送成功'
      }
    })
    module.exports = router
    
  • 相关阅读:
    redis:aof恢复与rdb服务器间迁移
    redis的主从服务器配置
    redis:消息发布与订阅频道
    redis:hash哈希类型的操作
    redis:order set有序集合类型的操作(有序集合)
    redis:set集合类型的操作(无序集合)
    redis:list列表类型的操作
    C#之多线程
    C# 操作FTP
    C# 导出导入TXT文件
  • 原文地址:https://www.cnblogs.com/superlizhao/p/12132123.html
Copyright © 2011-2022 走看看