web-dev-qa-db-ja.com

複数のユーザークラスを使用したFlask-Loginの実装

ユーザーとして機能する複数のクラス(たとえば、学校のアカウントとスタッフのアカウント)を持つアプリを作成しています。 Flask-Loginを使用してこれを簡単にしようとしていますが、その方法がよくわかりません。そのため、ユーザーがログインしたときに、ユーザー名が学校のアカウントに属しているかどうかをアプリで確認できます。またはスタッフアカウントを作成し、適切にログインします。

アカウントのどのtypeに属しているかを把握する方法を知っています(すべてのユーザー名は一意である必要があるため)。しかし、その後、その特定のユーザーにログインするようにアプリに指示する方法がわかりません。

現在、ユニバーサルログインページは1つしかありません。スタッフアカウントと学校アカウントに別々のログインページを作成すると簡単ですか?私はFlask-SQLAlchemyを介してMySQLデータベースを使用しています。

17
Ashu Goel

各ユーザーを特定の役割で定義できます。たとえば、ユーザー「x」を「SCHOOL」、ユーザー「y」を「STAFF」にすることができます。

class User(db.Model):

    __tablename__ = 'User'
    id = db.Column(db.Integer,primary_key=True)
    username = db.Column(db.String(80),unique=True)
    pwd_hash = db.Column(db.String(200))
    email = db.Column(db.String(256),unique=True)
    is_active = db.Column(db.Boolean,default=False)
    urole = db.Column(db.String(80))


    def __init__(self,username,pwd_hash,email,is_active,urole):
            self.username = username
            self.pwd_hash = pwd_hash
            self.email = email
            self.is_active = is_active
            self.urole = urole

    def get_id(self):
            return self.id
    def is_active(self):
            return self.is_active
    def activate_user(self):
            self.is_active = True         
    def get_username(self):
            return self.username
    def get_urole(self):
            return self.urole

ただし、Flask-loginにはまだユーザーロールの概念がなく、それをオーバーライドするために独自のバージョンのlogin_requiredデコレーターを作成しました。したがって、次のようなものを使用することをお勧めします。

def login_required(role="ANY"):
    def wrapper(fn):
        @wraps(fn)
        def decorated_view(*args, **kwargs):

            if not current_user.is_authenticated():
               return current_app.login_manager.unauthorized()
            urole = current_app.login_manager.reload_user().get_urole()
            if ( (urole != role) and (role != "ANY")):
                return current_app.login_manager.unauthorized()      
            return fn(*args, **kwargs)
        return decorated_view
    return wrapper

次に、このデコレータを次のようなビュー関数で使用できます。

@app.route('/school/')
@login_required(role="SCHOOL")
def restricted_view_for_school():
    pass
39
codegeek

@codegeekありがとう、これはとても便利だと思いました。コードを少し変更して機能させる必要があったので、他の人に役立つ場合に備えて、ここにドロップすることにしました。

from functools import wraps

login_manager = LoginManager()

...

def login_required(role="ANY"):
    def wrapper(fn):
        @wraps(fn)
        def decorated_view(*args, **kwargs):
            if not current_user.is_authenticated():
              return login_manager.unauthorized()
            if ((current_user.role != role) and (role != "ANY")):
                return login_manager.unauthorized()
            return fn(*args, **kwargs)
        return decorated_view
    return wrapper
10
Chockomonkey

これはあなたができることの例です。私はFlask-SQLAlchemyを使用した経験がありませんが、方法はそれほど変わらないはずです。以下の例では、SQLAlchemyを直接使用しています。

まず、Baseから継承するユーザークラスを定義して、ORM(宣言型)でマッピングできるようにします。

class User(Base):

    __tablename__ = 'user_table'
    id = Column(Integer, primary_key=True)
    email = Column(String(45), unique=True)
    name = Column(String(45))
    pwd = Column(String(8))
    user_role = Column(String(15))

    __mapper_args__ = {
        'polymorphic_identity': 'user_table',
        'polymorphic_on': user_role
    }

親クラスクラスの準備ができたら、必要な役割ごとに異なるクラスを設定します。

class SchoolAccount(User):
    __tablename__ = 'school_account'
    id = Column(Integer, ForeignKey('user_table.id'), primary_key=True)
    representative_name = Column(String(45))

    __mapper_args__ = {
        'polymorphic_identity': 'school_account'
    } 

Flask-Loginを使用して、ユーザーにログインし、ロールに基づいてアクセスを制限します。

これは、2つの異なる役割を持つログインシステムの例です。これは、flask、flask-sqlalchemy、flask-loginの優れたチュートリアルです: http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-v-user-logins

3
lv10

Flask-Security の「RoleManagement」をご覧ください。 Flask-Loginと簡単に統合できます。

1
png

オプションは Flask User @ lv10の回答で述べられているようになります。それは多くのことを処理するユーザーへの抽象化を実装します、それらの1つは 役割ベースの認証 です。

コードは基本的に@codegeekの回答と同じですが、Userクラスの「urole」プロパティの名前を「roles」に変更し、roleは「name」プロパティを持つクラスにする必要があります(コピーして貼り付けることができます ドキュメント )。 login_requiredはすでにroles_requiredとして実装されているため、定義する必要はありません。したがって、@login_required(role='rolename')の代わりに@roles_required('rolename')があります。

セキュリティ上の理由からこのAPIを使い始めたばかりで、すばらしい経験になっています。パスワード、ユーザー認証、ユーザーロールに問題がある人には強くお勧めします。