一 、csrf验证
二、图形验证码
详见:flask项目1实战:2.2 flask框架下使用图片验证码
三、短信验证码
详见:[flask项目1实战:2.3 flask框架下使用图片验证码]
四、用户注册
1、用户注册业务逻辑分析
2、设计用户注册接口基本思路
- 对于接口的设计,我们要根据具体的业务逻辑,设计出适合业务逻辑的接口。
- 设计接口的思路:
2.1 分析要实现的业务逻辑:
- 明确在这个业务中涉及到几个相关子业务。
- 将每个子业务当做一个接口来设计。
2.2 分析接口的功能任务,明确接口的访问方式与返回数据:
- 请求方法(如GET、POST、PUT、DELETE等)。
- 请求地址。
- 请求参数(如路径参数、查询字符串、表单、JSON等)。
- 响应数据(如HTML、JSON等)。
3、用户注册接口设计(待梳理)
3.1请求方式
选项 | 方案 |
---|---|
请求方法 | POST |
请求地址 | /users |
3.2 请求参数:表单参数
参数名 | 类型 | 是否必传 | 说明 |
---|---|---|---|
password | string | 是 | 密码 |
password2 | string | 是 | 确认密码 |
mobile | string | 是 | 手机号 |
sms_code | string | 是 | 短信验证码 |
3.3 响应结果
响应结果 | 响应内容 |
---|---|
注册失败 | 响应错误提示 |
注册成功 | 重定向到首页 |
4、用户注册接口定义
- 接收参数
- 验证参数
- 必传参数是否为空
- 手机号是否符合规: r’1[345678]\d{9}’ ,防止恶意注册
- 两次密码是否一致
- 业务逻辑验证
- 验证短信验证码正确性:图形验证码就不再验证(图形验证码正确后,才会有短信验证码)
- 从redis取短信验证码进行验证
- 判断短信验证码是否过期
- 从redis中删除短信验证码:不管对错,都只能使用一次,防止撞库
- 判断用户填写的短信验证是否正确
- 检查手机号是否注册过:发送短信验证码时已验证过,可以不验证,(如果该字段不是unique,建议还是验证一下,因本次该段是unique,添加数据时,如果重复会报错,故此处可不验证,在保存数据时捕获异常)
- 查询手机号是否存在,如果有记录表示注册过,提示,否则可以注册
- 如果查询数据库错误,直接返回异常
- 密码加密:
- 对密码明文进行加密:调用密码加密算法
- 验证短信验证码正确性:图形验证码就不再验证(图形验证码正确后,才会有短信验证码)
- 将注册信息写入数据库
- 通过数据模型保存数据,注意数据提交和异常后的数据回滚
- 保存登录状态到session中
- 返回结果
@api.route("/users",methods=["POST"])
def register():
"""
注册
:param: 手机号 短信验证码 密码 确认密码
:return: json
"""
# 接收参数
request_dict = request.get_json()
mobile = request_dict.get("mobile")
sms_code = request_dict.get("sms_code")
password = request_dict.get("password")
password2 = request_dict.get("password2")
# 验证
if not all([mobile, sms_code, password, password2]):
return jsonify(errno=RET.PARAMERR, errmsg='参数不完整')
# 判断手机号格式
if not re.match(r'1[345678]\d{9}', mobile):
return jsonify(errno=RET.PARAMERR, errmsg='手机号格式错误')
# 判断两次密码是否一致
if password != password2:
return jsonify(errno=RET.PARAMERR, errmsg='两次密码不一致')
# 业务逻辑
# 从redis取短信验证码
try:
real_sms_code = redis_store.get("sms_code_%s" % mobile)
except Exception as e:
logging.error(e)
return jsonify(errno=RET.DBERR, errmsg='读取短信验证码异常')
# 判断短信验证码是否过期
if real_sms_code is None:
return jsonify(errno=RET.NODATA, errmsg='短信验证码失效')
# 删除redis中的短信验证码
try:
redis_store.delete("sms_code_%s" % mobile)
except Exception as e:
logging.error(e)
# 判断用户填写的验证码的正确性
real_sms_code=real_sms_code.decode()
if sms_code.lower()!=real_sms_code:
return jsonify(errno=RET.DATAERR, errmsg='短信验证码错误')
# 判断手机号是否存在
try:
user = User.query.filter_by(mobile=mobile).first()
except Exception as e:
logging.error(e)
else:
if user is not None:
# 表示手机号已经被注册过
return jsonify(errno=RET.DATAEXIST, errmsg='手机号已经存在')
# 保存数据(同时检测手机是否被注册过)
user = User(name=mobile, mobile=mobile)
user.passwd_hash(password)
try:
db.session.add(user)
db.session.commit()
except IntegrityError as e:
db.session.rollback()
logging.error(e)
return jsonify(errno=RET.DATAEXIST, errmsg='手机号已经存在')
except Exception as e:
# 回滚
db.session.rollback()
logging.error(e)
return jsonify(errno=RET.DBERR, errmsg='插入数据库异常')
# 保存登录状态到session中
session["name"] = mobile
session["mobile"] = mobile
session["user_id"] = user.id
return jsonify(errno=RET.OK, errmsg='注册成功')
五、用户注册优化
- 采用生产者消费者开发模式优化发送短信等待