Warm tip: This article is reproduced from serverfault.com, please click

Why isn't my current_user authenticated in flask-login?

发布于 2016-06-02 16:11:47

My goal is to make my home view (/) a login page. Once the user logs in, a different page is render depending on its role. When I login (/auth), I see that the username and password are correctly entered. It then attempts to render /, where it tells me that my user is not authenticated and renders /login. Here are the views that describe this:

Views

@app.route("/login")
def login():
    return flask.render_template('login.html')

@app.route("/", methods=["GET"])
def home():
    if current_user.is_authenticated:
        if current_user.is_admin():
            return flask.render_template('admin_index.html')
        return flask.render_template('user_index.html')
    logger.info("Not authenticated. Going back to login.")
    return flask.render_template('login.html')


@app.route("/auth", methods=["POST"])
def auth():
    username = request.form['username']
    password = request.form['password']
    user = db.session.query(User).filter(User.username == username).first()
    logger.info(user)
    logger.info("{0}: {1}".format(username, password))
    print("user exists? {0}".format(str(user != None)))
    print("password is correct? " + str(user.check_password(password)))
    if user and user.check_password(password):
        user.is_authenticated = True
        login_user(user)
        return flask.redirect(url_for('home'))
    return flask.redirect(url_for('login'))

The problem is that flask-login's current_user.is_authenticated is always returning False after I attempt to login. My created user is correctly created and committed to the database. Below is my User model with the necessary methods as per flask-login:

User model

class User(db.Model):
    """
    A user. More later.
    """

    __tablename__ = 'User'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(128), unique=True)
    hashed_password = db.Column(db.String(160))
    admin = db.Column(db.Boolean)

    def __init__(self, username, password="changeme123", admin=False):
        self.username = username
        self.set_password(password)
        self.admin = admin
        self.is_authenticated = False

    def is_active(self):
        return True

    def is_authenticated(self):
        return self.is_authenticated

    def is_anonymous(self):
        return False

    def is_admin(self):
        return self.admin

    def get_id(self):
        return self.id

    def __repr__(self):
        return '<User {0}>'.format(self.username)

    def set_password(self, password):
        self.hashed_password = generate_password_hash(password)

    def check_password(self, password):
        return check_password_hash(self.hashed_password, password)

Here is the load_user function:

load_user

@login_manager.user_loader
def load_user(user_id):
    try:
        return User.query.get(User.id==user_id)
    except:
        return None

Why is current_user.is_authenticated returning False? I presumed that login_user(user) would make current_user == user, i.e., the one who is being authenticated in /auth, but it seems this is not the case.

Questioner
erip
Viewed
0
13.8k 2016-06-03 22:54:15

You have a method named User.is_authenticated. Inside User.__init__, though, you set an attribute with the same name.

self.is_authenticated = False

This overrides the method. Then, whenever you check current_user.is_authenticated, you are accessing the attribute that's always false.

You should remove the assignment from __init__ and change is_authenticated to the following:

def is_authenticated(self):
    return True

If you need it to be dynamic for some reason, rename the attribute so it doesn't shadow the method.

def is_authenticated(self):
    return self._authenticated

Another problem is with your load_user function.

Instead of filtering for User.id==user_id, you are getting it. The user wasn't being returned because load_user is returning User.query.get(True) instead of User.query.get(user_id).

If you make the following change, it will work:

@login_manager.user_loader
def load_user(user_id):
    try:
        return User.query.get(user_id)
    except:
        return None