Flask-Login问题:认证和重定向后,current_user仍然是AnonymousUserMixin类型。

问题描述 投票:0回答:0

我有一个使用自定义FlaskForm(使用WTForms)的登录页面。如果用户输入了正确的凭证,PostgreSQL数据库就会被成功查询(使用flask-sqlalchemy),以查看是否存在一个具有该名称和(散列)密码的用户。如果有这样一个用户,login_user(user)就会被运行,并尝试重定向到我的网站的主页。

我已经实现了flask-login(根据在线文档),但是当用户提供有效的登录凭证时,他们会被重定向到登录页面(就像他们没有提供有效的凭证一样)。我使用的是Google Chrome浏览器。

我已经确定在重定向到主页后,current_user的类型是AnonymousUserMixin(尽管登录函数中的current user的类型是User(我已经定义了,继承了UserMixin的所有方法)。

下面是我的尝试。

  • 确保我的代码符合Flask文档中列出的规范
  • 浏览了StackOverflow、Reddit和各种博客上的文章。从这些文章中,我对我的代码做了以下修改。

  • 在登录表单中插入了 hidden_tag() 和 csrf_token() 字段(见最后的代码摘录)

  • 为我的Flask应用程序添加了一个秘密密钥

  • 对当前用户的id进行编码和解码(用utf8)(见下面的代码,也在下面的用户类定义中)。

    return str(self.id).encode('utf-8').decode('utf-8')

根据 flask-login文档我在我的文件application.py(我的flask代码所在的文件)中加入了以下内容。

在文件的顶部:

login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'

一个用户加载器函数

@login_manager.user_loader
def load_user(id):
    id = db.execute("SELECT id FROM users WHERE id=:id", {"id": id})
    return User.get(current_user, id)

一个用户类(继承UserMixin)。

class User(UserMixin):
    is_active = True
    is_anonymous = False
    def __init__(self, email, name, id, input_password_hash):
        self.id = id
        self.name = name
        self.email = email
        self.password_hash = input_password_hash

    def check_password(self, password, password_hash_byte_literal):
        return bcrypt.checkpw(password.encode('utf8'), password_hash_byte_literal)

    def get_id(self):
        return str(self.id).encode('utf-8').decode('utf-8')

    def get(self, user_id):
        id = db.execute("SELECT id FROM users WHERE id=:user_id", {"user_id": user_id})
        if id:
            name = db.execute("SELECT name FROM users WHERE id=:user_id", {"user_id": user_id})
            email = db.execute("SELECT email FROM users WHERE id=:user_id", {"user_id": user_id})
            password_hash = db.execute("SELECT password_hash FROM users WHERE id=:user_id", {"user_id": user_id})
            user_name_string = ''
            user_email_string = ''
            user_password_hash_string = ''
            for row in name:
                for i in range(len(row)):
                    user_name_string += row[i]
            for row in email:
                for i in range(len(row)):
                    user_email_string += row[i]
            for row in password_hash:
                for i in range(len(row)):
                    user_password_hash_string += row[i]
            return User(user_email_string, user_name_string, user_id, user_password_hash_string)
        else:
            return None

下面是我的登录路径。

@app.route("/login", methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        email = form.email.data
        password = form.password.data
        user_pw_hash = (db.execute("SELECT password_hash FROM users WHERE email=:email", {"email": email}).fetchone())
        user_id = (db.execute("SELECT id FROM users WHERE email=:email", {"email": email}).fetchone())
        if user_id:
            password_hash_string = ''
            id_string = str(user_id)
            for row in user_pw_hash:
                for i in range(len(row)):
                    password_hash_string += row[i]
            user_id_int = int(id_string[1])
            user = User.get(user, user_id_int)
            password_hash_byte_literal = bytes(password_hash_string, encoding='utf8')
            correct_password = User.check_password(user, password, password_hash_byte_literal)
            if correct_password:
                login_user(user)
                next = url_for("index")
                if not is_safe_url(next, {"http://127.0.0.1:5000"}):
                    return abort(400)
                return redirect(next or url_for("login"))
            else:
                return render_template("login.html", message="Incorrect username or password.", form=form)
        else:
            return render_template("login.html", message="No account with that email address was found.", form=form)

    else:
        return render_template("login.html", form=form)

根据flask-login文档,我用login_user函数登录用户(见上图),然后检查下一个url(我的主页--"index")是否安全。如果是的话,我继续将用户重定向到该页面。

另外,下面是我的登录表单(其中包括hidden_tag()和csrf_token()字段)。

<form method="post" action="/login">
    {{ form.hidden_tag() }}
    {{ form.csrf_token() }}
    {{ wtf.form_field(form.email) }}
    {{ wtf.form_field(form.password) }}
    <button type="submit" value="submit">Submit</button><br>
</form>

我意识到这段代码在执行PostgreSQL命令之前还没有正确地对输入进行消毒。我将尽快解决这个问题。

导入。

import os
from flask import flash, Flask, session, redirect, render_template, request, url_for
from flask_bootstrap import Bootstrap
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
from flask_session import Session
from is_safe_url import is_safe_url
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from forms import LoginForm, RegistrationForm, ReviewForm   # Custom WTForms I wrote
import bcrypt

当用户提交表格并试图重定向到主页时的命令行输出(索引)

127.0.0.1 - - [15Jun2020 18:42:35]"GET登录HTTP1.1" 200 - "GET登录HTTP1.1"。

127.0.0.1 - - [15Jun2020 18:42:48] "POST login HTTP1.1" 302 -

127.0.0.1 - - [15Jun2020 18:42:48]"GET HTTP1.1" 302 - "GET HTTP1.1"。

127.0.0.1 - - [15Jun2020 18:42:48] "GET login?next=%2F HTTP1.1" 200 -

我正在使用Visual Studio代码(及其PowerShell)来运行和编辑这个Flask应用程序。

版本。

Windows 10
Google Chrome Version 83.0.4103.106 (Official Build) (64-bit)
bcrypt 3.1.7
email-validator 1.1.1
Python 3.8.2
Flask 1.1.2
Flask-WTF 0.14.3
Flask-SQLAlchemy 2.4.3
Flask-Session 0.3.2
Flask-Login 0.5.0
Flask-Bootstrap
WTForms 2.3.1
SQLAlchemy 1.3.16
mysql-connector-python 8.0.19
mysql-client 0.0.1
Jinja2 2.11.2
itsdangerous 1.1.0
is-safe-url 1.0

先谢谢您的帮助!

python flask flask-login
© www.soinside.com 2019 - 2024. All rights reserved.