简体   繁体   中英

Issues using Azure AAD in flask application factory blueprint files

I am attempting to use the Flask application factory pattern in order to tidy up my code base.

I am able to get this working in a single file as provided by Microsoft Here .

I understand for sqlalchemy I am creating the DB object in the models.py, importing it into my init file, and then I can import and utilize it in any of my blueprint files.

I am wanting to achieve the same thing with the azure auth functionality. At the moment I get an error because in the azure auth file it doesn't know what "app" is to set it up.

Error:

Traceback (most recent call last):
  File "C:\Program Files\Python310\lib\runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Program Files\Python310\lib\runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "C:\Users\Ben\PycharmProjects\applicationfactoryeexamplke\venv\lib\site-packages\flask\__main__.py", line 3, in <module>
    main()
  File "C:\Users\Ben\PycharmProjects\applicationfactoryeexamplke\venv\lib\site-packages\flask\cli.py", line 1047, in main
    cli.main()
  File "C:\Users\Ben\PycharmProjects\applicationfactoryeexamplke\venv\lib\site-packages\click\core.py", line 1055, in main
    rv = self.invoke(ctx)
  File "C:\Users\Ben\PycharmProjects\applicationfactoryeexamplke\venv\lib\site-packages\click\core.py", line 1657, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "C:\Users\Ben\PycharmProjects\applicationfactoryeexamplke\venv\lib\site-packages\click\core.py", line 1404, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "C:\Users\Ben\PycharmProjects\applicationfactoryeexamplke\venv\lib\site-packages\click\core.py", line 760, in invoke
    return __callback(*args, **kwargs)
  File "C:\Users\Ben\PycharmProjects\applicationfactoryeexamplke\venv\lib\site-packages\click\decorators.py", line 84, in new_func
    return ctx.invoke(f, obj, *args, **kwargs)
  File "C:\Users\Ben\PycharmProjects\applicationfactoryeexamplke\venv\lib\site-packages\click\core.py", line 760, in invoke
    return __callback(*args, **kwargs)
  File "C:\Users\Ben\PycharmProjects\applicationfactoryeexamplke\venv\lib\site-packages\flask\cli.py", line 911, in run_command
    raise e from None
  File "C:\Users\Ben\PycharmProjects\applicationfactoryeexamplke\venv\lib\site-packages\flask\cli.py", line 897, in run_command
    app = info.load_app()
  File "C:\Users\Ben\PycharmProjects\applicationfactoryeexamplke\venv\lib\site-packages\flask\cli.py", line 308, in load_app
    app = locate_app(import_name, name)
  File "C:\Users\Ben\PycharmProjects\applicationfactoryeexamplke\venv\lib\site-packages\flask\cli.py", line 218, in locate_app
    __import__(module_name)
  File "C:\Users\Ben\PycharmProjects\applicationfactoryeexamplke\myproject\__init__.py", line 11, in <module>
    from myproject.azureauth import ms_identity_web
  File "C:\Users\Ben\PycharmProjects\applicationfactoryeexamplke\myproject\azureauth.py", line 9, in <module>
    app.register_error_handler(NotAuthenticatedError,lambda err: (redirect(url_for('auth.sign_in', post_sign_in_url=request.url_rule))))
NameError: name 'app' is not defined

The aad.config.json file contains the app secrets needed for Azure authentication to work.

My File Structure is as follows:

Top Folder/
├─ aad.config.json
├─ myproject/
│  ├─ __init__.py
│  ├─ models.py
│  ├─ azureauth.py

In my __init__.py I have the following:

import os
from flask import Flask
from flask_session import Session
from ms_identity_web import IdentityWebPython
from ms_identity_web.adapters import FlaskContextAdapter
from ms_identity_web.errors import NotAuthenticatedError
from ms_identity_web.configuration import AADConfig

# Import the DB module and all the models
from myproject.models import db
from myproject.azureauth import ms_identity_web


aad_configuration = AADConfig.parse_json('aad.config.json')
AADConfig.sanity_check_configs(aad_configuration)


def create_app(test_config=None):
    app = Flask(__name__,instance_relative_config=True)
    app.config.from_mapping(
        SECRET_KEY="mysecretkey",
        SQLALCHEMY_DATABASE_URI='sqlite:///mydb.db',
        SESSION_TYPE="filesystem"
    )


    # Import all of the models from . being myproject. import the actual name as seen below

    from . import login


    # Setup DB as part of this app

    db.init_app(app)
    db.app = app

    # Register each blueprint so that the routes are accessable in the main application
    app.register_blueprint(login.bp)


    Session(app)

    # return the app
    return app

In my Models.py I have the following:

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()


class User(db.Model):
  __tablename__ = 'users'
  id = db.Column(db.Integer, primary_key=True)
  username = db.Column(db.String(64))
  email = db.Column(db.String(128))
  password_enc = db.Column(db.String(128))
  confirmed = db.Column(db.Boolean, default=False)

My Login.py :

from flask import Blueprint
from myproject.models import db,User


bp = Blueprint("user",__name__,url_prefix="/login")

@ms_identity_web.login_required
@bp.route("/")
def hello():
    db.create_all()
    test = User(username="Ben")
    db.session.add(test)
    db.session.commit()
    return("Hello user")

My azureauth.py :

from flask_session import Session
from ms_identity_web import IdentityWebPython
from ms_identity_web.adapters import FlaskContextAdapter
from ms_identity_web.errors import NotAuthenticatedError
from ms_identity_web.configuration import AADConfig



app.register_error_handler(NotAuthenticatedError,lambda err: (redirect(url_for('auth.sign_in', post_sign_in_url=request.url_rule))))
aad_configuration = AADConfig.parse_json('aad.config.json')
AADConfig.sanity_check_configs(aad_configuration)
adapter = FlaskContextAdapter(app) # ms identity web for python: instantiate the flask adapter
ms_identity_web = IdentityWebPython(aad_configuration, adapter)

I have tried various things, including putting the contents of the azure auth file in the main init file. This doesn't return any errors, but I cannot then import it in a blueprint to use the decorator of @ms_identity_web.login_required

I am wanting to set it up so I can use this decorator to protect any pages in any blueprint.

I can get this working in a singular python file 100% fine. Struggling to wrap my head around where application factories work differently.

In order to use the @ms_identity_web.login_required decorator (to protect blueprint endpoints) you need to pass it as an app variable:

For example, in your main app ( init .py):

app.config['ms_identity_web'] = ms_identity_web

And then in the blueprint location (azureauth.py):

app = current_app._get_current_object()
with app.app_context():
    ms_identity_web = current_app.config['ms_identity_web']

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM