Skip to content

注册

点击登录与注册页面之后的跳转

注册适配

后端路由编写好了之后,如果想要实现联调,就需要修改前端页面的逻辑。

  1. 没有登录之前不显示个人信息,只显示左上角的登录按钮,点击登录按钮调整到登录页面。
  2. 登录是没有账号,就先进行注册。注册页面如果有账号就跳转到登录页面。
  3. 注册账号成功之后跳转到登录页面
javascript
$(".register_btn").click(function () {
  layer.open({
    type: 1,
    title: '<h2 style="text-align: center">用户注册</h2>',
    content: $(".register_form"),
  });
});
html
<form
  class="layui-form register_form"
  style="display: none"
  lay-filter="register_form"
>
  <div class="layui-form-item">
    <div class="layui-input-wrap">
      <div class="layui-input-prefix">
        <i class="layui-icon layui-icon-username"></i>
      </div>
      <input
        type="text"
        name="nickname"
        value=""
        lay-verify="required"
        placeholder="昵称"
        autocomplete="off"
        class="layui-input"
        lay-affix="clear"
      />
    </div>
  </div>
  <div class="layui-form-item">
    <div class="layui-row">
      <div class="layui-col-xs7">
        <div class="layui-input-wrap">
          <div class="layui-input-prefix">
            <i class="layui-icon layui-icon-cellphone"></i>
          </div>
          <input
            type="text"
            name="mobile"
            value="18273174909"
            lay-verify="required|phone"
            placeholder="手机号"
            lay-reqtext="请填写手机号"
            autocomplete="off"
            class="layui-input"
            id="reg-mobile"
          />
        </div>
      </div>
      <div class="layui-col-xs5">
        <div style="margin-left: 11px;">
          <button
            type="button"
            class="layui-btn layui-btn-fluid layui-btn-primary"
            lay-on="reg-get-vercode"
          >
            获取验证码
          </button>
        </div>
      </div>
    </div>
  </div>
  <div class="layui-form-item">
    <div class="layui-input-wrap">
      <div class="layui-input-prefix">
        <i class="layui-icon layui-icon-vercode"></i>
      </div>
      <input
        type="text"
        name="vercode"
        value=""
        lay-verify="required"
        placeholder="短信验证码"
        lay-reqtext="请填写验证码"
        autocomplete="off"
        class="layui-input"
      />
    </div>
  </div>
  <div class="layui-form-item">
    <div class="layui-input-wrap">
      <div class="layui-input-prefix">
        <i class="layui-icon layui-icon-password"></i>
      </div>
      <input
        type="password"
        name="password"
        value=""
        lay-verify="required"
        placeholder="密码"
        autocomplete="off"
        class="layui-input"
        id="reg-password"
        lay-affix="eye"
      />
    </div>
  </div>
  <div class="layui-form-item">
    <div class="layui-input-wrap">
      <div class="layui-input-prefix">
        <i class="layui-icon layui-icon-password"></i>
      </div>
      <input
        type="password"
        name="confirmPassword"
        value=""
        lay-verify="required|confirmPassword"
        placeholder="确认密码"
        autocomplete="off"
        class="layui-input"
        lay-affix="eye"
      />
    </div>
  </div>

  <div class="layui-form-item">
    <input
      type="checkbox"
      name="agreement"
      lay-verify="required"
      lay-skin="primary"
      title="同意"
    />
    <a
      href="#terms"
      target="_blank"
      style="position: relative; top: 6px; left: -15px;"
    >
      <ins>用户协议</ins>
    </a>
  </div>
  <div class="layui-form-item">
    <button
      class="layui-btn layui-btn-fluid"
      lay-submit
      lay-filter="register-submit"
    >
      注册
    </button>
  </div>
  <div class="layui-form-item demo-reg-other">
    <label>已有帐号</label>
    <a href="javascript:;" style="color: #16baaa;" class="login_btn">请登录</a>
  </div>
</form>

切换到登录

如果有账号就跳转到登录页面,直接进行登录。

javascript
// 点击登录显示表单
$(".login_btn").click(function () {
  layer.closeAll("page");
  layer.open({
    type: 1,
    title: '<h2 style="text-align: center">用户登录</h2>',
    content: $(".login_form"),
  });
});

注册功能需求:

  • 使用手机号当前用户名进行注册
  • 注册的时候需要使用短信验证码进行验证

前端校验手机号

用户输入昵称、手机号码,点击获取验证码之前前端需要校验格式是否符合。

发送短信接口请看附录

1、输入手机号之后进行校验

javascript
layui.use(function () {
  var $ = layui.$;
  var form = layui.form;
  var layer = layui.layer;
  var util = layui.util;

  // 普通事件
  util.on("lay-on", {
    // 获取验证码
    "reg-get-vercode": function (othis) {
      let isvalid = form.validate("#reg-mobile"); // 主动触发验证
      // 验证通过
      if (isvalid) {
        // 此处可继续书写「发送验证码」等后续逻辑
        let data = form.val("register_form");
        // 发送请求
        $.ajax({
          type: "POST",
          contentType: "application/json",
          url: "/api/v1/send_sms_code",
          data: JSON.stringify({ mobile: data["mobile"] }),
          success: function (data) {
            // 处理后端的响应数据
            if (!data.code) {
              layer.msg(data.msg, { icon: 1 });
            } else {
              layer.msg(data.msg, { icon: 2 });
            }
          },
        });
      }
    },
  });
});

点击获取验证码之后,就会发送请求到后端,然后后端处理完之后返回结果给前端。

警告

在发送短信验证码之前需要验证图片验证码,以防止恶意发送短信验证码

Redis 缓存数据

在注册账号过程中,需要缓存图片验证码、手机短信验证码的内容,以及后续做缓存(cache)也需要使用,所以可以提前配置一下 redis。

shell
poetry add redis

初始化 redis

python
from redis import StrictRedis  # Redis


class RedisStore:
    def __init__(self, app=None):
        if app is not None:
            self.init_app(app)

        self.strict_redis: StrictRedis | None = None

    def init_app(self, app):
        # 配置 redis 数据库
        if "REDIS_HOST" not in app.config:
            raise Exception("请先配置 redis 信息")
        self.strict_redis = StrictRedis(
            host=app.config["REDIS_HOST"],
            port=app.config["REDIS_PORT"],
            decode_responses=True,
        )

        # current_app.strict_redis.xxx 的方式进行调用
        setattr(app, "strict_redis", self.strict_redis)

    def set_sms_code(self, mobile, code):
        self.strict_redis.set(f'sms_code_{mobile}', code, 60)

    def get_sms_code(self, mobile):
        return self.strict_redis.get(f'sms_code_{mobile}')


redis_store = RedisStore()
python
from .init_db import db, migrate
from .init_redis import redis_store  


def register_extensions(app):
    db.init_app(app)
    migrate.init_app(app, db)
    redis_store.init_app(app)  

后端发送短信验证码

后端获取数据之后

  1. 解析前端传递过来的手机号,然后进行校验
  2. 调用第三方工具下发注册短信验证码(腾讯云、阿里云就有对于的服务)
  3. 将手机号、短信验证码记录到数据库。下次提交时再进行校验
python
# filename: forum/apis/index.py
import re
from random import choices

from flask import Blueprint, current_app, request
from forum.extensions import redis_store

index_api = Blueprint('index_bp', __name__)


@index_api.post('/send_sms_code')
def send_sms_code_api():
    # 1. 解析前端传递过来的数据
    data = request.get_json()
    mobile = data['mobile']

    # 2. 校验手机号码
    pattern = r'^1[3-9]\d{9}$'
    ret = re.match(pattern, mobile)
    if not ret:
        return {
            'msg': '电话号码不符合格式',
            'code': -1
        }

    # 3. 发送短信验证码,并记录
    # 3.1 生成随机验证码
    code = choices('123456789', k=6)
    code = ''.join(code)

    # TODO 调用短信接口发送短信

    # 将验证吗缓存到 redis
    redis_store.set_sms_code(mobile, code)

    current_app.logger.warning(code)

    return {'code': 0, 'msg': '发送短信成功,短信验证码为:{}'.format(code)}

这是一个案例,没有调用腾讯云短信进行测试了,而是直接把正确结果返回。

对于短信与验证码缓存到 Redis 数据库了,下次请求注册时,再从里面进行提取。

腾讯云短信

腾讯云短信:https://cloud.tencent.com/product/sms

实现注册逻辑

前端逻辑

在手机收到短信验证码之后,前端填入验证码,然后再输入两次密码,点击同意协议按钮,就能实现注册。在这同时需要做验证验证码与密码。

javascript
layui.use(function () {
  var $ = layui.$;
  var form = layui.form;
  var layer = layui.layer;
  var util = layui.util;

  // 自定义验证规则
  form.verify({
    // 确认密码
    confirmPassword: function (value, item) {
      let passwordValue = $("#reg-password").val();
      if (value !== passwordValue) {
        return "两次密码输入不一致";
      }
    },
  });

  // 提交事件
  form.on("submit(register-submit)", function (data) {
    let field = data.field; // 获取表单字段值

    // 是否勾选同意
    if (!field.agreement) {
      layer.msg("您必须勾选同意用户协议才能注册");
      return false;
    }

    $.ajax({
      type: "POST",
      contentType: "application/json",
      url: "/api/v1/register",
      data: JSON.stringify(field),
      success: function (data) {
        // 处理后端的响应数据
        if (!data.code) {
          layer.msg(data.msg, { icon: 1 });
          setTimeout(function () {
            location.href = "/login";
          }, 2000);
        } else {
          layer.msg(data.msg, { icon: 2 });
        }
      },
    });

    return false; // 阻止默认 form 跳转
  });
});

后端逻辑

apis/index.py 中添加 register 视图函数,具体实现如下:

  1. 获取参数和判断是否有值
  2. 从 redis 中获取指定手机号对应的短信验证码的
  3. 校验验证码
  4. 初始化 user 模型,并设置数据并添加到数据库
  5. 保存当前用户的状态
  6. 返回注册的结果

视图函数代码

python
@index_api.post('/register')
def register():
    nickname = request.json.get('nickname')
    password = request.json.get('password')
    password2 = request.json.get('confirmPassword')
    mobile = request.json.get('mobile')
    sms_code = request.json.get('vercode')

    if password != password2:
        return {'code': -1, 'msg': '两次密码不一样,请重新输入'}

    local_sms_code = redis_store.get_sms_code(mobile)
    if sms_code != local_sms_code:
        return {'code': -1, 'msg': '短信验证码不一样,请重新输入'}

    user = UserORM()
    user.nickname = nickname
    user.password = password
    user.mobile = mobile
    user.save()
    return {'code': 0, 'msg': '注册成功'}