Question

I have difficulty in using the Flask-Login framework for authentication. I have looked through the documentation as thoroughly as possible but apparently I am missing something obvious.

class User():
    def __init__(self, userid=None, username=None, password=None):
        self.userid = userid
        self.username = username
        self.password = password

    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.userid)

    def __repr__(self):
        return '<User %r>' % self.username

def find_by_username(username):
    try:
        data = app.mongo.db.users.find_one_or_404({'username': username})

        user = User()
        user.userid = data['_id']
        user.username = data['username']
        user.password = data['password']
        return user

    except HTTPException:
        return None


def find_by_id(userid):
    try:
        data = app.mongo.db.users.find_one_or_404({'_id': userid})
        user = User(data['_id'], data['username'], data['password'])
        return user

    except HTTPException:
        return None

The above is my User class located in users/models.py

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

@login_manager.user_loader
def load_user(userid):
return find_by_id(userid)

The above is my user loader.

@mod.route('/login/', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        pw_hash = hashlib.md5(form.password.data).hexdigest()
        user = find_by_username(form.username.data)
        if user is not None:
            if user.password == pw_hash:
                if login_user(user):
                    flash('Logged in successfully.')
                    return redirect(request.args.get('next') or url_for('users.test'))
                else:
                    flash('Error')

        else:
            flash('Username or password incorrect')

    else:
        flash('Username or password incorrect')

return render_template('users/login.html', form=form)

There is no apparently error message, but when trying to access any views decorated with @login_required, it redirects me to the login form. Best as I can tell, the login_user function isn't actually working although it returns True when I called it. Any advice appreciated.

Was it helpful?

Solution

After stepping through a debugger for a while, I finally fixed the problem.

The key issue is that I was attempting to use the _id parameter from the MongoDB collection as the userid. I did not realize that the _id parameter was an ObjectID type instead of a string or unicode which I needed.

def find_by_username(username):
    try:
        data = app.mongo.db.users.find_one_or_404({'username': username})

        user = User(unicode(data['_id']), data['username'], data['password'])
        return user

    except HTTPException:
        return None


def find_by_id(userid):
    try:
        data = app.mongo.db.users.find_one_or_404({'_id': ObjectId(userid)})
        user = User(unicode(data['_id']), data['username'], data['password'])
        return user

Modifying the two functions appropriately fixed this error.

OTHER TIPS

If you've verified it's not your login_user function, then that leaves your find_by_id function.

The source code for the user_loader says:

The function you set should take a user ID (a unicode) and return a user object, or None if the user does not exist.

Your find_by_id function uses find_one_or_404 which raises an eyebrow. I'd add some extra debugging around that function, add some prints, or logging to show it's being called, with the correct unicode id, and that it's returning a User object, or None.

Hopefully that'll get you closer to narrowing down the problem.

I can't seem to find the place where you assign the user_id to the session after validating the form:

session['user_id'] = form.user.id

Have a look at this SimpleRegistrationForm on Github as an example

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top