TypeError: Object of type Cursor is not JSON serializable when comparing request.form.get and db value

TypeError: Object of type Cursor is not JSON serializable when comparing request.form.get and db value

我正在使用 Flask 编写一个简单的 Web 应用程序,并尝试实现登录过程。我的 /register 似乎工作正常,用户名和散列密码在注册时被正确插入我的数据库。但是,当涉及到登录部分时,我似乎无法比较存储在 MySQL 中的用户名和来自 resquest.form.get 的用户名,我收到以下错误消息:TypeError: Object of type Cursor is不可 JSON 序列化。

这是我的代码:

@app.route('/login', methods=["GET", "POST"])
def login():
    
    db = sqlite3.connect("users.db")
    c = db.cursor()

    if request.method== "POST":
        username = request.form.get("username")
        password = request.form.get("password")
        pwd_hash = sha256(password.encode('utf-8')).hexdigest()

        # Ensure username was submitted
        if not request.form.get("username"):
            flash("must provide username", "error")
            return redirect("/login")

        # Ensure password was submitted
        elif not request.form.get("password"):
            flash("must provide password", "error")
            return redirect("/login")

        # Query database for username
        if (c.execute("SELECT COUNT(*) FROM users WHERE username=:username", {"username" : username}).fetchall()[0][0] == 0):
            flash("invalid username", "error")
            return redirect("/login")
        
        if (c.execute("SELECT password FROM users WHERE(username=:username)", {"username": username}).fetchall()[0][0] != pwd_hash):
            flash("invalid password", "error")
            return redirect("/login")
        
        # Remember which user has logged in
        session["user_id"] = c.execute("SELECT username FROM users WHERE(:username=:username)", {"username": username})

        # Redirect user to home page
        return redirect("/")

    # User reached route via GET (as by clicking a link or via redirect)
    else:
        return render_template("login.html")

有什么想法吗?

您没有在此处获取行:

session["user_id"] = c.execute("SELECT username FROM users WHERE(:username=:username)", {"username": username})

c.execute() returns 游标对象,不能将其放入会话变量中。应该是

session["user_id"] = c.execute("SELECT username FROM users WHERE(:username=:username)", {"username": username}).fetchone()[0]

但似乎没有理由在这里再做一次查询。它只是 return 参数中的相同用户名。所以只写

sesion["user_id"] = username

顺便说一句,通常认为区分无效用户名和无效密码的安全设计很差。只需使用用户名和密码进行一次查询。如果失败,报告“用户名或密码无效”。

        if (c.execute("SELECT COUNT(*) FROM users WHERE username=:username AND password=:password", {"username" : username, "password": pwd_hash}).fetchone()[0] == 0):
            flash("invalid username or password", "error")
            return redirect("/login")

其他问题:

  1. 您正在从 request.form 参数中分配变量,然后再检查它们是否已实际填充。
  2. 如果您只需要一行,请使用 fetchone() 而不是 fetchall()[0]