web-dev-qa-db-ja.com

フラスコ管理でフラスコ管理パネルを保護する方法

Flaskを使用して作成され、管理インターフェイスを提供するためにflask-adminと統合された安全なWeb APIを探しています。フラスコの管理者が/adminおよびデフォルトでは誰でもアクセスできます。認証システムは提供されず、セキュリティを提供するために何が使用されるかを想定していないため、完全にオープン(セキュリティなし)です。このAPIは本番環境で使用する必要があるため、 URLにアクセスするすべての人に対して/adminルートを開くことができません。適切な認証が必要です。

views.pyでは、/adminルートを単に配置し、デコレータを介して認証を提供することはできません。これは、flask-adminによってすでに作成された既存のルートを上書きしてエラーを引き起こすためです。

さらなる調査により、flask-adminflask-securityの2つのモジュールがあることがわかりました。 flask-adminには、それを保護するためのis_accessibleメソッドがあることは知っていますが、flask-securityが提供する機能の多くは提供していません。

エンドポイント/adminに加えて、/adminで始まる/admin/<something>で始まる他のすべてのエンドポイントを保護する方法は見つかりませんでした。

私は特にフラスコセキュリティでこのタスクを行うことを探しています。それが不可能な場合は、代替案を提案してください。

PS:ngnix自体をロックできることはわかっていますが、それが最後のオプションになります。私がflask-securityを介して認証システムを持つことができれば、それは良いことです。

20
Sanyam Khurana

Flask-Security-Admin プロジェクトを確認してください。あなたが探しているものをかなり明確にカバーしていると思います。

上記のリンクから直接取得:

  • アプリのホームページに初めてアクセスすると、Flask-Securityのおかげでログインを求められます。
  • [email protected]とpassword = passwordでログインすると、「エンドユーザー」の役割になります。
  • [email protected]とpassword = passwordでログインすると、「admin」ロールが付与されます。
  • どちらのロールにもホームページへのアクセスが許可されています。
  • どちらのロールも/ adminページへのアクセスを許可されています。ただし、「admin」の役割がない場合、このページにはユーザーと役割の管理用のタブは表示されません。
  • / admin/userviewなどの/ adminページのサブページへのアクセスは、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')

これがお役に立てば幸いです。

9
RamiMac

これは「flask-security secure admin」のgoogle検索の最初の結果であり、すぐに使用できるソリューションはまだないので、貢献できると思います。

同様の質問がフラスコ管理プロジェクト Issue List で尋ねられ、フラスコ-ログインとmogodbを使用した簡単な例が提供されています ここ

SQLAchemyを使用して、sqliteデータベースとフラスコセキュリティの例を作成しました。以下のサンプルflaskアプリをご覧ください:

 #!/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)

ログインページのカスタマイズ方法 については、flask-securityのドキュメントを参照してください。

お役に立てれば。

12
guilhermerama

@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

3
seaders

Flask-Adminドキュメントにセキュリティに関するセクションがあります: http://flask-admin.readthedocs.io/en/latest/introduction/#authorization-permissions

1
Joes