AttributeError: module 'flask_login.login_manager' has no attribute 'user_loader' when using Flask login without modal

Viewed 2271

I have the following code that I am trying to do authentication using Flask:

from flask import Flask
from flask_login import LoginManager, login_manager
from auth.auth import auth_bp
from environments.environments import environments_bp
from migration.migration import migration_bp
from logs.logs import logs_bp

UPLOAD_FOLDER = 'static/uploads'

@login_manager.user_loader
def load_user(user_id):
    # since the user_id is just the primary key of our user table, use it in the query for the user
    return True

def create_app():

    app = Flask(__name__)

    app.register_blueprint(auth_bp, url_prefix='/auth')
    app.register_blueprint(environments_bp, url_prefix='/environments')
    app.register_blueprint(migration_bp, url_prefix='/migration')
    app.register_blueprint(logs_bp, url_prefix='/logs')

    app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
    app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'

    login_manager_copy = LoginManager()
    login_manager_copy.login_view = 'auth.login'
    login_manager_copy.init_app(app)

    return app

I am not using any database and the authentication is just a hardcoded if check as this is for an internal tool for single time usage.

How can fix this error ?

1 Answers

You are decorating the load_user function before your LoginManager() object is created in your app factory create_app()

For a nicely organized application, you should configure the LoginManager to work with your app inside your app factory as you are trying to do now.

def create_app():
    app = Flask(__name__)
    ...
    login_manager = LoginManager()
    login_manager.init_app(app)
    ...
    return app

Then in your authorization blueprint you access the login_manager in your the app object proxy current_app, and you define your load_user call back function there

from flask import current_app as app
...
...
@app.login_manager.userloader # Here your app is already created and configured with login manager
def load_user(_id):
    #Get your user from the database or where ever you are storing your user information and construct the user object to return
    if user_found:
      return user
    else:
      return None
...
...

Don't forget they you will also need save_user function that you call to save the user (you can choose to save it on a DB or any other place you see fit)on successful login.

Now with every request this callback function will be called and it will reload the user object you saved using the userID stored in the session (cookie for example). If it finds a user with the corresponding ID, it will construct the user object as per you logic in the load_user callback function, and you will have a user proxy called current_user that you can access within the request's context

For example within a GET request you can do

if current_user.age < 19:
  raise Unauthorized("Too young to rent a car")

I strongly recommend reading the Flask-Login documentation thoroughly and it will make it easier to understand the flow.

Related