注册
点击登录与注册页面之后的跳转
注册适配
后端路由编写好了之后,如果想要实现联调,就需要修改前端页面的逻辑。
- 没有登录之前不显示个人信息,只显示左上角的登录按钮,点击登录按钮调整到登录页面。
- 登录是没有账号,就先进行注册。注册页面如果有账号就跳转到登录页面。
- 注册账号成功之后跳转到登录页面
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)
后端发送短信验证码
后端获取数据之后
- 解析前端传递过来的手机号,然后进行校验
- 调用第三方工具下发注册短信验证码(腾讯云、阿里云就有对于的服务)
- 将手机号、短信验证码记录到数据库。下次提交时再进行校验
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
视图函数,具体实现如下:
- 获取参数和判断是否有值
- 从 redis 中获取指定手机号对应的短信验证码的
- 校验验证码
- 初始化 user 模型,并设置数据并添加到数据库
- 保存当前用户的状态
- 返回注册的结果
视图函数代码
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': '注册成功'}