zoukankan      html  css  js  c++  java
  • 测试平台系列(8) 与前端联调注册/登录接口(part 1)

    与前端联调注册/登录接口

    前方高能

    咱们今天讲的内容,可能和前端关联比较大,如果没有经验的同学,或者说只想专注后端的同学,你们直接copy前端的代码即可。

    秉着毁人不倦的思想,笔者打算细讲一部分前端的内容,毕竟还有一部分读者是前后兼修的。

    如果你们也想React相关知识,在我这里可能不能系统地学到,但是在 测试平台(序) 中也介绍了相关的前端学习建议和地址,希望大家恶补一下,毕竟这方面也不算难。

    编写登录接口

    与注册接口类似,甚至更加简单,先理一下思路:

    用户通过页面(这里暂时还没有)输入用户名密码,点击登录按钮进行登录,如果成功的话则将用户信息放入返回即可。如果用户名或者密码不正确,则给出提示,拒绝让用户登录!

    Talk is cheap, show me the code!

    from datetime import datetime

    from sqlalchemy import or_

    from app.middleware.Jwt import UserToken
    from app.models import db
    from app.models.user import User
    from app.utils.logger import Log


    class UserDao(object):
        log = Log("UserDao")

        @staticmethod
        def register_user(username, name, password, email):
            """

            :param username: 用户名
            :param name: 姓名
            :param password: 密码
            :param email: 邮箱
            :return:
            """

            try:
                users = User.query.filter(or_(User.username == username, User.email == email)).all()
                if users:
                    raise Exception("用户名或邮箱已存在")
                # 注册的时候给密码加盐
                pwd = UserToken.add_salt(password)
                user = User(username, name, pwd, email)
                db.session.add(user)
                db.session.commit()
            except Exception as e:
                UserDao.log.error(f"用户注册失败: {str(e)}")
                return str(e)
            return None

        @staticmethod
        def login(username, password):
            try:
                pwd = UserToken.add_salt(password)
                # 查询用户名/密码匹配且没有被删除的用户
                user = User.query.filter_by(username=username, password=pwd, deleted_at=None).first()
                if user is None:
                    return None"用户名或密码错误"
                # 更新用户的最后登录时间
                user.last_login_at = datetime.now()
                db.session.commit()
                return user, None
            except Exception as e:
                UserDao.log.error(f"用户{username}登录失败: {str(e)}")
                return None, str(e)

    简单解释一下,我们这边新建了一个login的方法,接受参数是usernamepassword,接着我们通过orm筛选出第一条username与password匹配且没有被删除的用户。

    注意: 如果这里没有这个用户的话,user变量会是None,所以我采用了判断None的方式

    最后我们把该用户的最后登录时间改成了当前时间。然后提交到了orm的session,这句话等同于执行sql。

    思考

    我们在上一个接口里面,注册完用户以后哈,是没有返回User实例信息的,但是这个接口不同,用户登录以后,需要拿到用户的信息以及token给前端处理。

    但是我们的用户实例并不是一个JSON对象,所以我们要为它做一些处理。

    接着我们编写pity/handler/factory.py,目的是为了转换orm对象为dict

    from datetime import datetime


    class ResponseFactory(object):

        @staticmethod
        def model_to_dict(obj, *ignore: str):
            data = dict()
            for c in obj.__table__.columns:
                if c.name in ignore:
                    # 如果字段忽略, 则不进行转换
                    continue
                val = getattr(obj, c.name)
                if isinstance(val, datetime):
                    data[c.name] = val.strftime("%Y-%m-%d %H:%M:%S")
                else:
                    data[c.name] = val
            return data

        @staticmethod
        def model_to_list(data: list, *ignore: str):
            return [ResponseFactory.model_to_dict(x, *ignore) for x in data]

    解释一下2个方法,第一个是将User此类实例转换为dict。由于orm实例都继承了db.Model类,所以他们都有__table__属性,也就有了相关字段的信息。

    ignore参数是一个可变字符串参数,当我们遇到需要忽略掉的字段时,可以派上用场。

    这里可以看到笔者针对datetime类对象做了特殊处理,这是因为JSON中没有对应的datetime格式,所以我们需要对他也进行转换。

    剩下的字段,直接通过set key value的方式赋值给data字典即可。

    model_to_list也比较简单,属于一个列表生成式,对每条orm实例都进行了转换,最终返回一个list(orm object)

    编写route方法

    最后我们就需要编写路由方法了,在pity/controller/auth/user.py新增如下方法:

    @auth.route("/login", methods=['POST'])
    def login():
        data = request.get_json()
        username, password = data.get("username"), data.get("password")
        if not username or not password:
            return jsonify(dict(code=101, msg="用户名或密码不能为空"))
        user, err = UserDao.login(username, password)
        if err is not None:
            return jsonify(dict(code=110, msg=err))
        user = ResponseFactory.model_to_dict(user, "password")
        token = UserToken.get_token(user)
        if err is not None:
            return jsonify(dict(code=110, msg=err))
        return jsonify(dict(code=0, msg="登录成功", data=dict(token=token, user=user)))

    这边还是先判断了username和password是否为空的情况,其次调用了UserDaologin方法,返回user和err信息。

    这里还有一个细节就是,我把用户的password给隐藏了

    user = ResponseFactory.model_to_dict(user, "password")`

    接着通过UserToken.get_token成功将对象转换成token,拿到token后返回了这样的对象:

    {
      "code"0,
      "data": {
        "user": {},
        "token"""
      }
    }

    验证

    依旧是熟悉的postman出场时间,简单地测试一下:

    • 密码错误的情形
    • 密码正确的返回

    可以看到,最后登录时间也正常显示了,token也生成了,password也没有暴露。想起抖音上的一些文案:

    婚期已定,父母满意,对我体贴.....

    有一种未来可期的感觉。

    求饶

    今天好像干货比较多,看来没有足够的时间留给前端联调了,会在下一节补充起来吧,至于名字就也不改了吧。

  • 相关阅读:
    POJ 2175 Evacuation Plan 费用流 负圈定理
    POJ 2983 Is the Information Reliable? 差分约束
    codeforces 420B Online Meeting
    POJ 3181 Dollar Dayz DP
    POJ Ant Counting DP
    POJ 1742 Coins DP 01背包
    中国儒学史
    产品思维30讲
    Java多线程编程核心技术
    编写高质量代码:改善Java程序的151个建议
  • 原文地址:https://www.cnblogs.com/we8fans/p/14507821.html
Copyright © 2011-2022 走看看