I'm trying to setup flask-security using the example at https://flask-security-too.readthedocs.io/en/stable/quickstart.html. I am using SQLAlchemy, not flask-sqlalchemy. I was able to get the example to work, but I'm having problems integrating it in my application. flask-security seems to require Base.query = db_session.query_property()
, which in turn, seems to require using scoped-session
, which I don't use (there seem to be some strong opinions against using it)
This seems to be a pretty weird requirement of flask-security
, which appears to be undocumented, except in the sample code. I'm just wondering if this will cause a problem with other parts of my application
There also seems to be some inconsistencies with various examples. Some of them attach the security object to the app with
app.security = Security(app, user_datastore)
and later uses
app.security.datastore.create_user(email="test@me.com"...
whereas in other places, I see
security = Security(app, user_datastore)
user_datastore.create_user(email="test@me.com"...
I'm trying to get around it by doing something like this
database.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from root.config import config
def get_engine():
return create_engine(config.get('db').get('DATABASE_URI'), echo=False)
# Use this session for everything other than flask-security
def get_session():
engine = get_engine()
return sessionmaker(bind=engine)()
app.py
import os
from flask import Flask
from flask_security import SQLAlchemySessionUserDatastore, Security, hash_password
from sqlalchemy.orm import scoped_session, sessionmaker
from root.db.ModelBase import ModelBase
from root.db.database import get_engine
from root.db.models import User, Role
from root.mail import mail_init
from root.views.calibration_views import calibration
nwm_app = Flask(__name__)
nwm_app.config["SECURITY_REGISTERABLE"] = True
# Use this session for flask-security
session = scoped_session(sessionmaker(bind=get_engine()))
# This is global. Is it going to affect other parts of my application if I'm using SQLAlchemy 'select'?
ModelBase.query = session.query_property()
user_datastore = SQLAlchemySessionUserDatastore(session, User, Role)
security = Security(nwm_app, user_datastore)
# Register blueprints or views here
nwm_app.register_blueprint(calibration)
# one time setup
with nwm_app.app_context():
# Create a user and role to test with
# nwm_app.security.datastore.find_or_create_role(
user_datastore.find_or_create_role(
# name="user", permissions={"user-read", "user-write"}
name="user"
)
print('created role')
session.commit()
# if not nwm_app.security.datastore.find_user(email="test@me.com"):
if not user_datastore.find_user(email="test@me.com"):
print('user not found')
# nwm_app.security.datastore.create_user(email="test@me.com",
user_datastore.create_user(email="test@me.com",
password=hash_password("password"), roles=["user"])
session.commit()
if __name__ == '__main__':
nwm_app.run()
Not a actionable answer - but there is a lot here. First - Flask-Security (FS) supports a few different datastores - but raw SQLAlchemy isn't one of them - close - but currently FS requires a managed session which Flask-SQLAlchemy and the scoped_session provide.
Second - as I am writing this, I am adding support for Flask-SQLAlchemy-Lite - which has a much thinner footprint than the old Flask-SQLAlchemy - and doesn't use scoped_sessions. Furthermore, as part of this support - I am updating to the 'new' sqlalchemy model of using 'select' rather than 'query' - so that issue will be gone. I believe that with this change - providing your own db.session will work - I'll try to test for that.