2015-06-27 266 views
15

我正在尋求保護使用燒瓶製作的Web API並與flask-admin集成以提供管理界面。我搜索並發現flask-admin的管理面板爲/admin,默認情況下任何人都可以訪問它。它沒有提供認證系統,並且完全打開(沒有任何安全性),因爲它們沒有假設用於提供安全性的內容。這個API必須在生產中使用,所以我們不能有一個打開/admin路線的每個人打網址。正確的認證是必要的。如何使用燒瓶安全保護燒瓶管理面板

views.py我不能簡單地把/admin路由,並通過裝飾提供認證,因爲這將覆蓋flask-admin已經創建的現有路由,這將導致錯誤。

進一步的研究表明,有兩個模塊flask-adminflask-security。我知道flask-adminis_accessible方法來保護它,但它不提供太多的功能,這是由flask-security提供的。

我還沒有找到任何方法來確保端點/admin加上從/admin開始的所有其他端點,如/admin/<something>

我正在尋找具體的瓶頸安全執行此任務。如果不可能,請提出替代方案。 PS:我知道我可以鎖定ngnix本身,但這將是最後的選擇。如果我可以通過flask-security認證系統,那會很好。

+1

Flask-Security的認證機制(通過Flask-Login)控制'current_user.is_authenticated()'的返回值。在你的'is_accessible'實現中返回這個(可能與某種角色/權限檢查相結合)應該讓你能夠在Flask-Admin中使用Flask-Security的保護。 – jonafato

回答

4

你應該看看Flask-Security-Admin項目,我認爲它涵蓋了非常清楚你在找什麼。

直接從上面的鏈接摘自:

  • 當你第一次訪問該應用程序的主頁,你會被提示登錄,由於瓶的安全性。
  • 如果您使用[email protected]和password = password登錄,您將擁有「最終用戶」角色。
  • 如果您使用[email protected]和password = password登錄,您將擁有「admin」角色。
  • 任一角色都被允許訪問主頁。
  • 任一角色都被允許訪問/ admin頁面。但是,除非您具有「管理員」角色,否則您將不會在此頁面上看到用於管理用戶和角色的選項卡。
  • 只有管理員角色被允許訪問/ admin/userview等/ admin頁面的子頁面。否則,你會得到一個「禁止」的迴應。
  • 請注意,編輯用戶時,感謝Flask-Admin會自動填充角色的名稱。
  • 您可以添加和編輯用戶和角色。由此產生的用戶將能夠登錄(除非你設置了active = false),如果他們有「admin」角色,將能夠執行管理。

相關的代碼位於main.py,並且清楚地註釋來解釋如何複製固定使用燒瓶安全燒瓶-管理面板的過程。

最基本的,相關的一塊你是以下(行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') 

我希望這是有幫助的。

+1

謝謝!經過一些進一步的挖掘和研究,我得到了它的工作。 –

+0

謝謝你提供這個。我一直在尋找答案一個小時,終於在這裏找到了你。 – applecrusher

1
+0

在發佈之前,我已經仔細研究了它,並在本節中展示了有關使用'flask-admin'而不是'flask-security'的示例。我特別希望通過'flask-security'來實現它,因爲它提供了更多'flask-login'功能。任何幫助,將不勝感激。 –

+0

@Joes https://stackoverflow.com/questions/46914054/access-control-for-flask-admin – Sparrowcide

6

因爲這是「flask-security secure admin」谷歌搜索的第一個結果,而且現在還沒有開箱即用的解決方案,所以我認爲我可以做出貢獻。

一個類似的問題,有人問燒瓶管理員項目Issue List和使用燒瓶登錄和mogodb一個簡單的例子,提供here

我做了一個使用sqlite數據庫和flask-security的SQLAchemy的例子。請參閱下面的示例應用程序燒瓶:

#!/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='[email protected]', 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) 

請參閱燒瓶安全文檔學習how to customize the login page

希望這會有所幫助。

0

我對所有子視圖使用@ RamiMac的答案,但對於索引1(默認爲/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