Python 如何使用多个蓝图处理flask中的登录?

Python 如何使用多个蓝图处理flask中的登录?,python,flask-login,flask,Python,Flask Login,Flask,我有多个蓝图需要集成到一个应用程序中。我正在使用flask login来处理登录。但是,我对如何处理蓝图的LoginManager()和.user\u加载程序感到困惑 这是我当前的文件结构 system/ run.py config.py app/ __init__.py models.py views/ blueprint1.py blueprint2.py

我有多个蓝图需要集成到一个应用程序中。我正在使用
flask login
来处理登录。但是,我对如何处理蓝图的
LoginManager()
.user\u加载程序
感到困惑

这是我当前的文件结构

system/
     run.py
     config.py
     app/
        __init__.py
        models.py
        views/
             blueprint1.py
             blueprint2.py
        static/
        templates/
              <templates>
系统/
run.py
config.py
应用程序/
__初始值
models.py
观点/
蓝图1.py
蓝图2.py
静止的/
模板/
正确的实施方法是什么?我是否只需在
\uuuu init\uuuuuu.py
处调用它们并在蓝图处导入login manager变量?或者我需要在设计图中单独给他们打电话


希望我能清楚地描述这个问题。感谢您阅读和回答

您必须了解,对于一个应用程序,无论您使用多少蓝图,您都必须使用一个登录管理器(当然,当蓝图是独立的时,可能会有特定的例外,但在这种情况下,您可能无法使用
flask登录
)。因为:

  • 你有一个入口点
  • 如果用户未登录,他将被重定向到登录/注册页面
  • 您有1个用户加载器
  • 登录管理器的工作原理:

  • 它在请求上下文中注册当前用户
  • 在请求读取会话之前,获取用户id,使用
    user\u loader
    加载用户,并将其设置为
    current\u user
    AnonymousUser
  • 当您访问私人页面时,
    login\u required
    检查
    当前用户。是否验证了当前用户()
  • 登录时,它会将用户id添加到会话中

  • 因此,您必须为flask应用程序仅初始化一个登录管理器实例,然后在所有蓝图中使用
    login\u required
    current\u user

    我就是这样处理的:

    这就是我初始化所有内容的地方:

    import logging
    import logging.config
    
    import flask
    import flask.globals as flask_global
    import flask_login
    
    from config import flask as flask_config
    from rest.api import dashboard
    from rest.api.util import login_decorator
    
    logger = logging.getLogger(__name__)
    
    # app
    flask_app = flask.Flask(__name__)
    flask_app.config.from_object(flask_config)
    
    # login manager needs be set before blueprint registration
    login_manager = flask_login.LoginManager()
    login_manager.init_app(flask_app)
    
    flask_app.register_blueprint(dashboard.blueprint)
    
    
    # setting blueprint specific login view
    # login_manager.login_view = "login"
    
    
    @login_manager.user_loader
    def load_user(user_id):
        """
        This will be used many times like on using current_user
        :param user_id: username
        :return: user or none
        """
        # http://librelist.com/browser/flask/2012/4/7/current-blueprint/#44814417e8289f5f5bb9683d416ee1ee
        blueprint = flask_global.current_app.blueprints[request.blueprint]
    
        if hasattr(blueprint, load_user):
            return blueprint.load_user(user_id)
    
        # https://flask-login.readthedocs.org/en/latest/#how-it-works
        return None
    
    以下是我自己处理登录的蓝图:

    from __future__ import absolute_import
    
    import flask
    import flask_login
    from flask import Blueprint
    
    from core.models.profile import Agent
    from core.utils import thread_local
    from rest.api.util import login_decorator
    
    blueprint = Blueprint('human', __name__, url_prefix='/human')
    
    
    def load_user(user_id):
        """
        This will be used many times like on using current_user
        :param user_id: username
        :return: user or none
        """
        agent = None
        try:
            agent = Agent.objects.get(username=user_id)
        except:
            # https://flask-login.readthedocs.org/en/latest/#how-it-works
            pass
        return agent
    
    
    @blueprint.record_once
    def on_load(state):
        """
        http://stackoverflow.com/a/20172064/742173
    
        :param state: state
        """
        blueprint.load_user = load_user
        state.app.login_manager.blueprint_login_views[blueprint.name] = 'human.login'
    
    
    @blueprint.route('/login', methods=['POST'])
    @login_decorator.login_not_required
    def login():
        username = flask.request.args.get('username')
        password = flask.request.args.get('password')
        try:
            agent = Agent.objects.get(username=username)
        except:
            return 'Invalid username'
    
        if not agent.check_password(password):
            return 'Invalid password'
    
        flask_login.login_user(agent)
    
        return 'Valid login'
    
    
    @blueprint.route("/logout")
    def logout():
        flask_login.logout_user()
        return 'Logout done'
    
    
    @blueprint.before_request
    def before_request():
        agent = flask_login.current_user
        # https://flask-login.readthedocs.org/en/latest/#anonymous-users
        is_logged_in = agent.get_id() is not None
    
        login_not_required = getattr(flask.current_app.view_functions[flask.request.endpoint], 'login_not_required', False)
        is_static_resource_call = flask.request.endpoint.startswith('static/')
    
        if is_static_resource_call or is_logged_in or login_not_required:
            if is_logged_in:
                thread_local.set_current_brand_id(agent.brand_id)
        else:
            flask.abort(401)
            # if we want to redirect to some page then we can use this. The appropriate login_view should be set
            # return flask.current_app.login_manager.unauthorized()
    

    希望有帮助。

    如果由于文档不太清楚,任何人仍然面临这一挑战,这里有一个解决方案

    在您的情况下,您需要将登录管理器声明与flask应用程序实例放在同一个文件中。这通常是一个
    \uuuuu init\uuuuuuuuuuuupy.py
    文件,带有
    app=Flask(\uuuuuu name\uuuuuuuuuu)。
    在顶部,导入LoginManager类

    from flask_login import LoginManager
    
    然后将其绑定到应用程序实例

    login_manager = LoginManager()
    login_manager.init_app(app)
    
    (这不是问题,只是以防万一有人需要它)假设您有管理员和普通用户,并且您正在从不同的表进行身份验证:

    @login_manager.user_loader
    def load_user(user_id):
        x = Users.query.get(str(user_id))
        if x == None:
            x = Admins.query.get(str(user_id))
        return x
    
    最后,在导入蓝图之后,您可以在字典中为每个蓝图定义登录视图

    login_manager.blueprint_login_views = {
        'admin': '/admin/login',
        'site': '/login',
    }
    

    由于您将登录管理器绑定到flask应用程序实例,因此无需将其导入任何blueprint

    中,这正是我所需要的。非常感谢。这意味着我不能对多个实例使用登录管理器?与管理员页面和用户页面一样?请注意,query.get()与“where primary\u key\u field=user\u id”相同,因此如果您拥有>=与管理员相同的用户数,那么这将永远不会搜索管理员表,假设两者都是自动递增的int-PKsNice点。从来没有想过这一点,因为我所有的主键通常都是uuid4()。嗨,我在这里假设您对站点和管理员有不同的登录。如果我只有一种类型的用户(和多个蓝图),该怎么办?这种方法行得通吗?是的,应该行得通。您只需要删除查询admin表的if语句。