注册————续上篇
一、定义注册的路由
-
新建passport.py 文件,注册到蓝图的视图
-
定义路由函数的参数——手机号、验证码、密码,密码2
-
路由的返回参数格式—json
-
整体逻辑
-
校验参数
-
判断手机号格式
-
判断密码是否一致
-
从redis 取出短信验证码
-
判断验证码是否过期
-
删除redis短信验证码,防止重复使用
-
比较短信验证码是否正确
-
判断手机号是否注册过(因为db数据库手机号唯一,所以可以直接看保存到数据库是否重复来判断是否注册)
-
保存用户到数据库(用 类. 属性 的方法设置值)
-
保存登陆状态
-
返回结果
# passport.py from . import api from flask import request, jsonify, current_app, session from ihome.utils.response_code import RET from ihome import redis_store, db from ihome.models import User from sqlalchemy.exc import IntegrityError from werkzeug.security import generate_password_hash, check_password_hash import re @api.route("/users",methods=["POST"]) def register(): """" 注册:返回json格式 参数:手机号,验证码,密码,密码2 """ req_dict = request.get_json() mobile = req_dict.get("mobile") sms_code = req_dict.get("sms_code") password = req_dict.get("password") password2 = req_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: current_app.logger.error(e) return jsonify(errno=RET.DATAERR, 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: current_app.logger.error(e) # 判断短信验证码是否正确 if real_sms_code != sms_code: return jsonify(errno=RET.DATAERR, errmsg="短信验证码输入错误") # # 判断手机号是否注册过 # try: # user = User.query.filter_by(mobile=mobile).first() # except Exception as e: # current_app.logger.error(e) # return jsonify(errno=RET.DBERR, errmsg="数据库异常") # else: # if user is not None: # return jsonify(errno=RET.DATAEXIST, errmsg="手机号已存在") # 保存用户信息到数据库 user = User(name=mobile,mobile=mobile) # # 类.方法 调用 # user.generate_password_hash(password) # 类.属性的方法设置值 user.password = password try: db.session.add(user) db.session.commit() except IntegrityError as e: # s数据库操作异常后回滚 db.session.rollback() # 手机号出现了重复值,手机号已经注册过 current_app.logger.error(e) return jsonify(errno=RET.DATAEXIST, errmsg="手机号已存在") except Exception as e: db.session.rollback() current_app.logger.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, essmsg="注册成功")
-
-
密码加密算法
调用flask 的werkzeug.security 下的generate_password_hash方法
加密原理: 随机生成: 盐值 加密算法 结果
password=“12345” + “abc” sha1 abc$ sdjhgjgfjh
取值:abc + password 的加密算法
在模型类models.py 下的User类,引入这个方法生成password_hash 值,
用 装饰器 @property 会把函数变为属性,属性名即为函数名
# models.py Class User(): # 加上property装饰器,会把函数变为属性,属性名即为函数名 @property def password(self): """读取属性的函数行为""" # print(user.password) # 读取属性是被调用 # # 函数返回值会做为属性值 # return "xxxxx" raise AttributeError("这个属性只能设置,不能读取") @password.setter def password(self, value): """ 设置属性 user.password = value :param value: 设置属性的数据 用户输入传入的密码 :return: """ self.password_hash = generate_password_hash(value)
连接到调用方法
user.password = password
二、测试后端
用postman 发送请求做测试,模仿前端发送的json 数据
TIP: 测试时出现错误:csrf 错误,而ihome 配置中的
CSRFProtect(app)
防护机制只是代表后端防护机制开启,但是前端并没有传过来boby请求体中的csrf_token值,所以测试后端时先关闭,连接前端时在开启然后补充csrf![csrf防护过程](G:\百度网盘\BaiduNetdiskDownload\python课件18\基础班-就业班课件资料 -1-4位基础班 5-14就业班\10-web全栈开发阶段-爱家租房项目\17-爱家租房项目\第二天\csrf防护过程.png)
![开启csrf防护机制](G:\百度网盘\BaiduNetdiskDownload\python课件18\基础班-就业班课件资料 -1-4位基础班 5-14就业班\10-web全栈开发阶段-爱家租房项目\17-爱家租房项目\第二天\开启csrf防护机制.png)
三、前端编写和连接后端数据
前端默认提交的是form 表单,现在为表单的提交补充自定义的函数行为 (提交事件e)
// register.js // js读取cookie的方法,将csrf_token取出,方便后端csrf进行验证 function getCookie(name) { var r = document.cookie.match("\\b" + name + "=([^;]*)\\b"); return r ? r[1] : undefined; } $(".form-register").submit(function(e){ // 阻止浏览器对于表单的默认自动提交行为 e.preventDefault(); var mobile = $("#mobile").val(); var phoneCode = $("#phonecode").val(); var passwd = $("#password").val(); var passwd2 = $("#password2").val(); if (!mobile) { $("#mobile-err span").html("请填写正确的手机号!"); $("#mobile-err").show(); return; } if (!phoneCode) { $("#phone-code-err span").html("请填写短信验证码!"); $("#phone-code-err").show(); return; } if (!passwd) { $("#password-err span").html("请填写密码!"); $("#password-err").show(); return; } if (passwd != passwd2) { $("#password2-err span").html("两次密码不一致!"); $("#password2-err").show(); return; } // 调用ajax向后端发送注册请求 var req_data = { mobile: mobile, sms_code: phoneCode, password: passwd, password2: passwd2, }; var req_json = JSON.stringify(req_data); $.ajax({ url: "/api/v1.0/users", type: "post", data: req_json, contentType: "application/json", dataType: "json", headers: { "X-CSRFToken": getCookie("csrf_token") }, // 请求头,将csrf_token值放到请求中,方便后端csrf进行验证 success: function (resp) { if (resp.errno == "0") { // 注册成功,跳转到主页 location.href = "/index.html"; } else { alert(resp.errmsg);弹出提示框 } } }) }); })