登录后,flask-login用户设置为匿名

时间:2015-05-10 11:04:25

标签: python flask flask-login

我对烧瓶和烧瓶登录很新,并且我已经在这几天挣扎了。

我试图像这样记录用户:

from creds import auth_username, auth_password, pgsql_dbuser, pgsql_dbpassword, pgsql_db1name
from flask import Flask, render_template, request, Response, redirect, url_for
from flask.ext.bcrypt import Bcrypt
from flask.ext.login import LoginManager, login_required, login_user, current_user, logout_user
import logging
import psycopg2
import uuid
import datetime

app = Flask(__name__)
app.secret_key = str(uuid.uuid4()) # <- required by login_manager.init_app(app)

bcrypt = Bcrypt(app)
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'index'


@app.route('/', methods=['GET','POST'])
def index():
        page_name = '/'
        if request.method == 'POST':
                email = request.form['email']
                candidate_password = request.form['password']
                user = finduserindbbyemail(email)
                if user != None:
                        password_hash = checkuserpasswordindb(email)
                        if bcrypt.check_password_hash(password_hash, candidate_password):
                                user_object = User(user)
                                result = login_user(user_object) # <- here for successful login
                                return redirect(url_for('loggedin', user_object=type(user_object), user=user, result=result, current_user=current_user))
                        else:
                                user_object = User(user)
                                error_message = "The password you entered is incorrect"
                                return render_template('index.html', error_message=error_message)
                else:
                        error_message = "The email address you entered does not match any we have in our records"
                        return render_template('index.html', error_message=error_message)

        if request.method == 'GET':
                return render_template('index.html')

我有一个User类和一个用户回调:

class User():

        def __init__(self, user):
                self.user = user

        def is_authenticated(self):
                return True

        def is_active(self):
                return True

        def is_anonymous(self):
                return False

        def get_id(self):
                return unicode(self.user)

@login_manager.user_loader
def load_user(user):
        con = psycopg2.connect(database=pgsql_db1name, user=pgsql_dbuser, password=pgsql_dbpassword, host='localhost')
        uuid = "'"+user+"'"
        cur = con.cursor()
        cur.execute("SELECT uuid FROM users WHERE uuid = "+ uuid)
        uuid = cur.fetchone()
        con.close()
        if uuid != None:
                user = unicode(uuid[0])
                return User.get_id(user)
        else:
                return None

验证成功后(显然?),用户被重定向到一个登录页面,该页面有一个@login_required装饰器。但是,不是加载登录页面,应用程序将用户重定向到登录页面,告诉我用户没有登录? 如果尝试向页面发送值并删除@login_required装饰器,以便我可以看到该页面,这就是我在登录后在浏览器中看到的内容&#39;:

current_user.is_authenticated() = False
current_user.is_active() = False
current_user.is_anonymous() = True
current_user.get_id() = None
user_object = <type 'instance'>
user = 2ca1296c-374d-43b4-bb7b-94b8c8fe7e44
login_user = True
current_user = <flask_login.AnonymousUserMixin object at 0x7f2aec80f190> Logout

看起来我的用户还没有被记录并且被视为匿名? 谁能看到我做错了什么?我很难理解这应该如何运作。

3 个答案:

答案 0 :(得分:2)

所以..我设法让它工作,但没有使用user_loader回调。无论出于何种原因,我的用户加载器都表现出与此相同的行为: Flask-login with static user always yielding 401- Unauthorized

无论如何,我使用了一个request_loader回调,而不是基于这个例子: http://gouthamanbalaraman.com/blog/minimal-flask-login-example.html

所以对于登录的用户,从这里开始:

if bcrypt.check_password_hash(password_hash, candidate_password):
    user_object = User(user, password_hash)
    result = login_user(user_object) # <- here for successful login
    token = user_object.get_auth_token(user, password_hash) 
    return redirect(url_for('loggedin', token=token))

我创建了一个用户对象,其中包含用户的id和密码哈希值。 然后我登录用户。然后我使用itsdangerous创建用户ID和密码哈希的时间序列化标记。 get_auth_token函数是User类的一部分。它看起来像这样:

class User():

    def __init__(self, user, password_hash):
        self.user = user
        self.password = password_hash
        .
        .
        .
    def get_auth_token(self, user, password):
        data = [str(self.user), self.password]
        return serializer.dumps(data, salt=serializer_secret)

你需要在代码的开头创建一个序列化器:

serializer = URLSafeTimedSerializer(serializer_secret)

因此,在创建令牌后,将其作为URL查询参数传递给登录视图。 当您尝试加载login_required页面时,例如我的登录页面,这是login_user在成功登录后重定向到的位置,将执行request_loader回调。它看起来像这样:

@login_manager.request_loader
def load_user_from_request(request):
    if request.args.get('token'):
        token = request.args.get('token')
        max_age = 1
        try:
            data = serializer.loads(token, salt=serializer_secret, max_age=max_age)
            username = data[0]
            password_hash = data[1]
            found_user = finduserindbbyuuid(username)
            found_password = checkuserpasswordindbbyuuid(username)
            if found_user and found_password == password_hash:
                user_object = User(found_user, password_hash)
                if (user_object.password == password_hash):
                    return user_object
                else:
                    return None
            else:
                return None

        except BadSignature, e:
            pass
    else:
        return None

这是我的user_loader失败的地方。我已成功登录,但user_loader始终返回None,因此我的用户将被视为匿名。

因此,对于请求加载器,它会检查请求URL是否包含“令牌”#39;查询字符串中的参数。如果是这样,它需要它的价值并使用它的危险,反序列化数据。 您可以使用定时序列化器使令牌过期,但也有非定时序列化器。令牌反序列化后,取用户和密码哈希并检查数据库是否存在,这与user_loader应该工作的方式完全相同..我想?我的user_loader没有用,所以我很可能做错了。

无论如何,如果用户和密码在数据库中匹配,则返回用户对象和bam,登录工作。

我不确定我是不是以正确的方式做到这一点,因为我的裤子几乎要飞得很好。我看到人们使用token_loader而不是request_loader回调函数加载令牌的示例,但我无法弄清楚如何设置&amp;获取身份验证令牌给&amp;来自客户。也许生病了......有一天......

如果你有同样的问题,也许这可能会有所帮助?或者只是让我知道你的想法

欢呼声

答案 1 :(得分:0)

在您通过登录表单后,可能无法登录用户或current_user的另一个原因是匿名的:在数据库中的用户上设置了active = false标志。在docs中确认了此行为:

  

flask_login.login_user(用户,记住= False,持续时间=无,强制= False,新鲜= True)[源代码]   登录用户。您应该将实际的用户对象传递给该用户。如果用户的is_active属性为False,则除非强制为True,否则他们将不会登录。

     

如果登录尝试成功,它将返回True;否则,将返回False(即,由于用户处于非活动状态)。

因此,当您调用login_user时,您可以执行以下操作: login_user(user, remember=form.remember_me.data, force=True),如果要允许不活动的用户登录。

答案 2 :(得分:0)

我在搜索Flask-Login + Flask-Dance的帮助时找到了此页面。我在带有current_user装饰器的处理程序中看到AnonymousUserMixin@login_required。就我而言,请确保@app.route@login_required上方的行中已解决了该问题。正确的顺序在文档中:https://flask-login.readthedocs.io/en/latest/#flask_login.login_required