爱租家项目注册开发流程

注册————续上篇

一、定义注册的路由

  • 新建passport.py 文件,注册到蓝图的视图

  • 定义路由函数的参数——手机号、验证码、密码,密码2

  • 路由的返回参数格式—json

  • 整体逻辑

    1. 校验参数

    2. 判断手机号格式

    3. 判断密码是否一致

    4. 从redis 取出短信验证码

    5. 判断验证码是否过期

    6. 删除redis短信验证码,防止重复使用

    7. 比较短信验证码是否正确

    8. 判断手机号是否注册过(因为db数据库手机号唯一,所以可以直接看保存到数据库是否重复来判断是否注册)

    9. 保存用户到数据库(用 类. 属性 的方法设置值)

    10. 保存登陆状态

    11. 返回结果

      #  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 数据

    1539174392283

    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);弹出提示框
                    }
                }
            })
    
        });
    })
    

猜你喜欢

转载自blog.csdn.net/F_Liberalism/article/details/83956671