【云短信】个人开发的小项目,如何用上短信验证码登录/注册?

3,338 阅读3分钟

前言

短信验证登录 / 注册是目前很主流的一种登录模式,对于小型企业或者个人开发者而言,这种登录方式可以足够自然地拿到用户的电话号码,也能确保操作者就是用户本人,有一定的安全保障。

在我的毕设中,我设计的用客户端登录方式就是短信验证码登录。这篇文章会着重讲一下作为个人开发者(无企业资质),是如何完成短信验证码登录的。

技术选项:Node.js(Koa2)、Mysql、阿里云短信服务

实现过程

做功能之前先搞清楚需求。我的小项目中,登录这方面的需求就是:短信验证码登录,没有登录过的用户自动完成注册并且登录。它整个的业务逻辑并不复杂,大体模块可以分为这两个:发送验证码 + 验证并且登录。

发送验证码

演示效果

先看看演示效果。发送验证码应该是一个单独的接口。这里的业务逻辑是 接收使用户手机号 -> 生成随机数 -> 将随机数和手机号存入临时表单 -> 请求阿里云短信服务向用户发送验证码。

//生成随机数
const randomCode = function () {
  var str = "0123456789";
  var result2 = "";
  for (var i = 6; i > 0; --i)
    result2 += str[Math.floor(Math.random() * str.length)];
  return result2;
};

生成随机数之后,相对于的是要将用户的手机号码和验证码存入临时表单以待验证。这里涉及到技术选型的问题,一般来说处理这些缓存类的数据主流用的是Redis,它可以设置缓存的有效期,也可以减少数据库的读写压力。但因为是个人的小项目,这里我只用Mysql实现。

存入临时表单

login_code表设计

login_code的这个表很简单,只有phone和code两个字段。这里涉及到一个验证码有效时长的问题,当然了,Mysql也是支持定时事件线程的(如果需要,可以看看mysql相关的文章),但是这里我想让服务器定时删除就好。

验证码存入流程

//代码过长,这里贴出sql指令供理解

let isSend = `select * from login_code where phone = ${myphone}`,
     
  if (isSend) {
    `update login_code set code= ${codemsg} where phone = ${myphone}`
  } else {
     `INSERT INTO login_code (phone,code) values(${myphone},${codemsg})`
  }

setTimeout(async () => {
    `DELETE FROM login_code WHERE phone=${myphone} and code=${codemsg}`
  }, 300000);

如果是正式的项目,这部分内容最好是用Redis实现。

阿里云短信服务

短信云服务必不可少。市场上有好几家云短信服务,腾讯云、阿里云、华为云... ...都是不错的选择,价格也差不太多。这里强调一下最好还是选大公司的云服务,默默吐槽一下之前作为备选的榛子云,注册他们自己网站的验证码都半天发不过来!最后我选的是阿里云,学生优惠打折的时候买很便宜,似乎是1000条1年20元。

具体可以看这里。

不过,由于相关政策的完善,云短信服务的签名和模板审核变得异常严格,对个人开发者的要求是:要具有已经备案的网站或者上线的程序,且具有验证码场景的功能。由于我有已经备案的个人博客,做一个类似验证码登录的页面就可以轻松通过审核了。

网站的服务器、域名及备案我都是用的阿里云的服务,都很方便,只是需要一些时间成本。

如果你还没有已经备案的网站,心急想实现功能,也可以去云市场里找第三方的服务。亲测也是可用的。这里贴一个,类似的都可以。

当申请到权限之后,调用就很简单了。只需要跟着官方的文档来,阿里云官方支持了语言的SDK,只要对应地复制到自己代码,配置好 AccessKey 和短信签名、模板即可。

登录 / 未登录过自动注册

登录逻辑

如上图,当用户收到验证码并且输入之后,点击登录按钮就是另一个接口了。

这时候先会去login_code(自我吐槽一下,其实验证码用 captcha 这个单词才对)这个表查询验证码和手机是否对的上,如果对得上的话就再查询 users 表中是否有该用户的记录。如果没有,就要先创建新用户再返回数据。这里会随机生成一个字符串,作为用户的token,在之后涉及到用户权限的接口中这个可以当成用户的唯一标识,放在请求头中。

//随机生成指定长度的字符串
const randomStrin = function (length) {
  var str = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  var result1 = "";
  for (var i = length; i > 0; --i)
    result1 += str[Math.floor(Math.random() * str.length)];
  return result1;
};

此外,还可以在创建新用户这里一些其它的功能。

比如说我的项目有一些社交成分,这里的设计就是:若是用户通过别人的分享完成注册的,分享的那个人就可以获得相对应的积分。下面贴一些基本逻辑和sql语句可以供参考。

	//篇幅所限,非完全代码,系基本逻辑和主要sql语句。
	let myphone = ctx.request.body.phone;
  let mycodemsg = ctx.request.body.code;

  let isCode = 
      `select * from login_code where phone = ${myphone} and code = ${mycodemsg}`,
      //若不存在返回flase

  if (!isCode) {
    //验证码不正确返回错误提示
    ctx.body = "验证码不正确";
    return;
  }

  // 判断是否注册过
  let isres = `SELECT * FROM users WHERE phone='${myphone}'`;
  //用户表不存在放回flase

  if (isres) {
    let loginSql = `select * from users where phone = ${myphone}`;
   //注册过返回用户数据
      ctx.body = result;
    
  } else {
    let myname = myphone;
    let mytoken = randomStrin(16);
    let mycode = randomStrin(8);//此处是邀请板块的邀请码,若是分享给其它用户就传这个
    let myavatar = "http://localhost:8090/useravatar/avatar.png";//默认的用户头像
    let resSql = `INSERT INTO users (name,phone,token,code,avatar,score) values("${myname}",${myphone},"${mytoken}","${mycode}","${myavatar}",0)`;
   //新增用户
    let result = `select * from users where token = "${mytoken}"`,
        //返回新用户信息
    });

    // 此处为邀请者得积分模块
   
    if (ctx.url.split("?")[1].split("=")[1]) {
      //这里的邀请参数放在了url中
      let invite_code = ctx.url.split("?")[1].split("=")[1];
      let invite_setting = "SELECT invite_setting FROM setting"//这里是邀请-积分比,放在了setting表单中

      let old_score_total  = `SELECT score,token FROM users where code="${invite_code}"`,
      
      let type = 1;
      let new_score_total = old_score_total.score + invite_setting;
      let invite_token = old_score_total.token;
      let creat_time = formatTime(new Date());
      let sql = `INSERT INTO score (token,type,score_change,score_total,creat_time) values("${invite_token}",${type},${invite_setting},${new_score_total},"${creat_time}")`;
      let changeuser = `update users set score=${new_score_total} where token="${invite_token}"`,
       //上列都是邀请-得积分板块的操作,如果有想法,在这里可以有很多种玩法
    }

    if (result) {
      ctx.body = result;
    }
  }

总结

短信验证登录 / 未登录过自动完成注册——这个模式已经成为了现在很多个人开发者和小网站的登录注册主流。实操下来,你会发现最费时间和精力的不是逻辑设计和代码的开发,而是如何获得向用户发送验证码。

云服务固然方便,但是因为审核的严格也有所限制。搞一个网站备案往往需要半个月十几天的时间。所以,如果你是大学生,也想在毕设之类的项目用上短信验证的话建议先去做网站备案,才能享受到各种方便的云服务。当然了,你也可以试试看我文中列出的云市场的服务,或者是弄邮箱认证也差不多是这样的流程。

个人小项目,有许多不足,欢迎你指正,与我交流哦~