Issue
I've set up Flask Admin and it is working, but am struggling with adding authentication. There are several tutorials I've followed but can't seem to get them to work with how I've set up my app. Per the documentation on Flask-Admin regarding authentication (and slightly tweaked based on how I'm importing various elements), you just need to add:
class AdminView(ModelView):
def is_accessible(self):
return current_user.is_authenticated
def inaccessible_callback(self, name, **kwargs):
# redirect to login page if user doesn't have access
return redirect(url_for('login', next=request.url))
But I can still access the /admin
route without logging in. (I also would like to add an additional conditional that checks that the user is listed as an admin, which is a boolean column in the user table, but I haven't gotten this first part to work).
I've tried putting the above inside and outside of the create_app()
function. Does this have to do with my blueprints? If so, where would I put this code?
# __init__.py
from flask import Flask
from dotenv import load_dotenv
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from flask_login import LoginManager, current_user
from flask_migrate import Migrate
from SIMS_Portal.config import Config
from flask_admin import Admin
from flask_admin.contrib.sqla import ModelView
from flaskext.markdown import Markdown
load_dotenv()
db = SQLAlchemy()
bcrypt = Bcrypt()
login_manager = LoginManager()
login_manager.login_view = 'users.login'
login_manager.login_message_category = 'danger'
mail = Mail()
from SIMS_Portal import models
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(Config)
db.init_app(app)
bcrypt.init_app(app)
login_manager.init_app(app)
mail.init_app(app)
admin = Admin(app, name='SIMS Admin Portal', template_mode='bootstrap4', endpoint='admin')
Markdown(app)
from SIMS_Portal.main.routes import main
from SIMS_Portal.assignments.routes import assignments
from SIMS_Portal.emergencies.routes import emergencies
from SIMS_Portal.portfolios.routes import portfolios
from SIMS_Portal.users.routes import users
from SIMS_Portal.errors.handlers import errors
app.register_blueprint(main)
app.register_blueprint(assignments)
app.register_blueprint(emergencies)
app.register_blueprint(portfolios)
app.register_blueprint(users)
app.register_blueprint(errors)
from SIMS_Portal.models import User, Assignment, Emergency, Portfolio, NationalSociety
admin.add_view(ModelView(User, db.session))
admin.add_view(ModelView(Assignment, db.session))
admin.add_view(ModelView(Emergency, db.session))
admin.add_view(ModelView(Portfolio, db.session))
admin.add_view(ModelView(NationalSociety, db.session))
return app
Solution
Got some help from the r/flask community which I'll share here for anyone else that has set their app up the same way and found existing tutorials unhelpful. The key when using an app factory like in my case is the swap out the ModelView for the AdminView you define, which can go before the create_app()
function. In my __init__.py
, I first defined that custom class that inherits from ModelView
(and add a check that the user is not only logged in but also listed as an admin in my database):
class AdminView(ModelView):
def is_accessible(self):
if current_user.is_admin == 1:
return current_user.is_authenticated
def inaccessible_callback(self, name, **kwargs):
return render_template('errors/403.html'), 403
Then within the create_app()
I swap out what I had previously included as admin.add_view(ModelView(User, db.session))
for admin.add_view(AdminView(User, db.session))
That little difference makes obvious sense, but again, I couldn't find tutorials that covered this.
Answered By - MightyModest
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.