如何使用 flask-security 保护 flask-admin 面板
How to secure the flask-admin panel with flask-security
我正在寻找使用 Flask 制作并与 flask-admin
集成以提供管理界面的安全 Web API。我搜索并发现 flask-admin 在 /admin
有一个管理面板,默认情况下任何人都可以访问它。它不提供身份验证系统并且完全开放(没有任何安全性),因为他们没有假设将使用什么来提供安全性。这个 API 必须在生产中使用,所以我们不能为每个点击 url 的人提供一个开放的 /admin
路由。需要正确的身份验证。
在 views.py
中,我不能简单地放置 /admin
路由并通过装饰器提供身份验证,因为那样会覆盖 flask-admin
已经创建的现有路由,这样会导致错误。
进一步研究发现有两个模块flask-admin
和flask-security
。我知道 flask-admin
有 is_accessible
方法来保护它,但它没有提供 flask-security
.
提供的很多功能
我没有找到任何方法来保护端点 /admin
以及所有其他以 /admin
开头的端点,例如 /admin/<something>
.
我正在寻找专门使用 flask-security 来完成这项任务。如果不可能,请提出替代方案。
PS:我知道我可以锁定 ngnix
本身,但那将是最后的选择。如果我可以通过 flask-security
拥有一个身份验证系统,那就太好了。
Flask-Admin 文档中有关于安全性的部分:http://flask-admin.readthedocs.io/en/latest/introduction/#authorization-permissions
您应该查看 Flask-Security-Admin 项目,我认为它非常清楚地涵盖了您正在寻找的内容。
直接取自上面的link:
- When you first visit the app's home page, you'll be prompted to log in, thanks to Flask-Security.
- If you log in with username=someone@example.com and password=password, you'll have the "end-user" role.
- If you log in with username=admin@example.com and password=password, you'll have the "admin" role.
- Either role is permitted to access the home page.
- Either role is permitted to access the /admin page. However, unless you have the "admin" role, you won't see the tabs for administration of users and roles on this page.
- Only the admin role is permitted to access sub-pages of /admin page such as /admin/userview. Otherwise, you'll get a "forbidden" response.
- Note that, when editing a user, the names of roles are automatically populated thanks to Flask-Admin.
- You can add and edit users and roles. The resulting users will be able to log in (unless you set active=false) and, if they have the "admin" role, will be able to perform administration.
相关代码位于 main.py 中,并有清晰的注释以解释如何复制使用 flask-security 保护 flask-admin 面板的过程。
最基本的、与您相关的部分如下(第 152- 行):
# Prevent administration of Users unless the currently logged-in user has the "admin" role
def is_accessible(self):
return current_user.has_role('admin')
希望对您有所帮助。
由于这是 "flask-security secure admin" google 搜索的第一个结果,并且还没有开箱即用的解决方案,我想我可以做出贡献。
有人在 flask-admin 项目 Issue List and a simple example using flask-login and mogodb is provided here 上提出了类似的问题。
我使用 SQLAchemy 为 sqlite 数据库和 flask-security 做了一个例子。请参阅下面的示例烧瓶应用程序:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import os.path as op
from flask import Flask, render_template, url_for, request
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.event import listens_for
from flask.ext.security import current_user, login_required, RoleMixin, Security, SQLAlchemyUserDatastore, UserMixin
from flask_admin import Admin, AdminIndexView
from flask_admin.contrib import sqla
# Create application
app = Flask(__name__)
# Create dummy secrety key so we can use sessions
app.config['SECRET_KEY'] = '123456790'
# Create in-memory database
app.config['DATABASE_FILE'] = 'sample_db.sqlite'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + app.config['DATABASE_FILE']
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
# Create directory for file fields to use
file_path = op.join(op.dirname(__file__), 'static/files')
# flask-security models
roles_users = db.Table('roles_users',
db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))
class Role(db.Model, RoleMixin):
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(80), unique=True)
description = db.Column(db.String(255))
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(255), unique=True)
password = db.Column(db.String(255))
active = db.Column(db.Boolean())
confirmed_at = db.Column(db.DateTime())
roles = db.relationship('Role', secondary=roles_users,
backref=db.backref('users', lazy='dynamic'))
# Create Security
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security = Security(app, user_datastore)
# Only needed on first execution to create first user
#@app.before_first_request
#def create_user():
# db.create_all()
# user_datastore.create_user(email='yourmail@mail.com', password='pass')
# db.session.commit()
class AnyModel(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Unicode(64))
def __unicode__(self):
return self.name
class MyAdminIndexView(AdminIndexView):
def is_accessible(self):
return current_user.is_authenticated() # This does the trick rendering the view only if the user is authenticated
# Create admin. In this block you pass your custom admin index view to your admin area
admin = Admin(app, 'Admin Area', template_mode='bootstrap3', index_view=MyAdminIndexView())
# Add views
admin.add_view(sqla.ModelView(AnyModel, db.session))
# To acess the logout just type the route /logout on browser. That redirects you to the index
@login_required
@app.route('/login')
def login():
return redirect('/admin')
@app.route('/')
def index():
return render_template('index.html')
if __name__ == '__main__':
# Build sample db on the fly, if one does not exist yet.
db.create_all()
app.run(debug=True)
请参考 flask-security 文档学习how to customize the login page。
希望对您有所帮助。
我对所有子视图都使用@RamiMac 的答案,但对于索引一(默认情况下 /admin
),我使用此方法,用需要的 admin
角色重新包装该方法查看。
@app.before_first_request
def restrict_admin_url():
endpoint = 'admin.index'
url = url_for(endpoint)
admin_index = app.view_functions.pop(endpoint)
@app.route(url, endpoint=endpoint)
@roles_required('admin')
def secure_admin_index():
return admin_index()
在我的项目中,这直接在我所有的 Flask-Admin
代码之后,它本身在它自己的启动脚本中,custom_flaskadmin.py
。
我正在寻找使用 Flask 制作并与 flask-admin
集成以提供管理界面的安全 Web API。我搜索并发现 flask-admin 在 /admin
有一个管理面板,默认情况下任何人都可以访问它。它不提供身份验证系统并且完全开放(没有任何安全性),因为他们没有假设将使用什么来提供安全性。这个 API 必须在生产中使用,所以我们不能为每个点击 url 的人提供一个开放的 /admin
路由。需要正确的身份验证。
在 views.py
中,我不能简单地放置 /admin
路由并通过装饰器提供身份验证,因为那样会覆盖 flask-admin
已经创建的现有路由,这样会导致错误。
进一步研究发现有两个模块flask-admin
和flask-security
。我知道 flask-admin
有 is_accessible
方法来保护它,但它没有提供 flask-security
.
我没有找到任何方法来保护端点 /admin
以及所有其他以 /admin
开头的端点,例如 /admin/<something>
.
我正在寻找专门使用 flask-security 来完成这项任务。如果不可能,请提出替代方案。
PS:我知道我可以锁定 ngnix
本身,但那将是最后的选择。如果我可以通过 flask-security
拥有一个身份验证系统,那就太好了。
Flask-Admin 文档中有关于安全性的部分:http://flask-admin.readthedocs.io/en/latest/introduction/#authorization-permissions
您应该查看 Flask-Security-Admin 项目,我认为它非常清楚地涵盖了您正在寻找的内容。
直接取自上面的link:
- When you first visit the app's home page, you'll be prompted to log in, thanks to Flask-Security.
- If you log in with username=someone@example.com and password=password, you'll have the "end-user" role.
- If you log in with username=admin@example.com and password=password, you'll have the "admin" role.
- Either role is permitted to access the home page.
- Either role is permitted to access the /admin page. However, unless you have the "admin" role, you won't see the tabs for administration of users and roles on this page.
- Only the admin role is permitted to access sub-pages of /admin page such as /admin/userview. Otherwise, you'll get a "forbidden" response.
- Note that, when editing a user, the names of roles are automatically populated thanks to Flask-Admin.
- You can add and edit users and roles. The resulting users will be able to log in (unless you set active=false) and, if they have the "admin" role, will be able to perform administration.
相关代码位于 main.py 中,并有清晰的注释以解释如何复制使用 flask-security 保护 flask-admin 面板的过程。
最基本的、与您相关的部分如下(第 152- 行):
# Prevent administration of Users unless the currently logged-in user has the "admin" role
def is_accessible(self):
return current_user.has_role('admin')
希望对您有所帮助。
由于这是 "flask-security secure admin" google 搜索的第一个结果,并且还没有开箱即用的解决方案,我想我可以做出贡献。
有人在 flask-admin 项目 Issue List and a simple example using flask-login and mogodb is provided here 上提出了类似的问题。
我使用 SQLAchemy 为 sqlite 数据库和 flask-security 做了一个例子。请参阅下面的示例烧瓶应用程序:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import os.path as op
from flask import Flask, render_template, url_for, request
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.event import listens_for
from flask.ext.security import current_user, login_required, RoleMixin, Security, SQLAlchemyUserDatastore, UserMixin
from flask_admin import Admin, AdminIndexView
from flask_admin.contrib import sqla
# Create application
app = Flask(__name__)
# Create dummy secrety key so we can use sessions
app.config['SECRET_KEY'] = '123456790'
# Create in-memory database
app.config['DATABASE_FILE'] = 'sample_db.sqlite'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + app.config['DATABASE_FILE']
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
# Create directory for file fields to use
file_path = op.join(op.dirname(__file__), 'static/files')
# flask-security models
roles_users = db.Table('roles_users',
db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))
class Role(db.Model, RoleMixin):
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(80), unique=True)
description = db.Column(db.String(255))
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(255), unique=True)
password = db.Column(db.String(255))
active = db.Column(db.Boolean())
confirmed_at = db.Column(db.DateTime())
roles = db.relationship('Role', secondary=roles_users,
backref=db.backref('users', lazy='dynamic'))
# Create Security
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security = Security(app, user_datastore)
# Only needed on first execution to create first user
#@app.before_first_request
#def create_user():
# db.create_all()
# user_datastore.create_user(email='yourmail@mail.com', password='pass')
# db.session.commit()
class AnyModel(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Unicode(64))
def __unicode__(self):
return self.name
class MyAdminIndexView(AdminIndexView):
def is_accessible(self):
return current_user.is_authenticated() # This does the trick rendering the view only if the user is authenticated
# Create admin. In this block you pass your custom admin index view to your admin area
admin = Admin(app, 'Admin Area', template_mode='bootstrap3', index_view=MyAdminIndexView())
# Add views
admin.add_view(sqla.ModelView(AnyModel, db.session))
# To acess the logout just type the route /logout on browser. That redirects you to the index
@login_required
@app.route('/login')
def login():
return redirect('/admin')
@app.route('/')
def index():
return render_template('index.html')
if __name__ == '__main__':
# Build sample db on the fly, if one does not exist yet.
db.create_all()
app.run(debug=True)
请参考 flask-security 文档学习how to customize the login page。
希望对您有所帮助。
我对所有子视图都使用@RamiMac 的答案,但对于索引一(默认情况下 /admin
),我使用此方法,用需要的 admin
角色重新包装该方法查看。
@app.before_first_request
def restrict_admin_url():
endpoint = 'admin.index'
url = url_for(endpoint)
admin_index = app.view_functions.pop(endpoint)
@app.route(url, endpoint=endpoint)
@roles_required('admin')
def secure_admin_index():
return admin_index()
在我的项目中,这直接在我所有的 Flask-Admin
代码之后,它本身在它自己的启动脚本中,custom_flaskadmin.py
。