認証と権限

安全概論

認証は,システムがそのユーザを安全に識別できる機構である.EVEは,基本認証,トークン認証,HMAC認証のいくつかの認証方式をサポートしている. OAuth2 integration 簡単にできます。

許可は、システムによって制御されたリソースに対する特定の(認証された)ユーザのアクセス権限レベルを決定する機構である。EVEでは、APIエンドポイントのすべてまたは一部へのアクセスを制限することができます。他の述語を保持しながら何らかのHTTP述語を保護することができます例えば、公共読み出し専用アクセスを許可することができ、ユーザがプロジェクトを作成して編集することのみを許可することができます。あなたはまだ許可することができます GET 要求されたアクセス権限と POST メソッドパラメータをチェックすることで他者にアクセス権限を提供する.役割ベースのアクセス制御もサポートされています。

安全はカスタマイズが非常に重要な分野の中の一つだ。それがあなたにいくつかの基本的な認証クラスを提供する理由だ。これらは基本的な認証機構を実現し、許可論理を実現するためにはサブクラスが必要である。どの認証案を選択しても、サブクラスの中で唯一しなければならないのは書き換えです check_auth() 方法です。

世界的なアイデンティティ検証

APIの認証を有効にするためには,アプリケーションのインスタンス化時にカスタム認証クラスを渡すだけでよい.私たちの例では BasicAuth 基本的には 基本的な身分検証 案:

from eve.auth import BasicAuth

class MyBasicAuth(BasicAuth):
    def check_auth(self, username, password, allowed_roles, resource,
                   method):
        return username == 'admin' and password == 'secret'

app = Eve(auth=MyBasicAuth)
app.run()

あなたのすべてのAPIエンドポイントは現在安全であり、これは、クライアントがAPIを使用するために正しい証明書を提供する必要があることを意味します:

$ curl -i http://example.com
HTTP/1.1 401 UNAUTHORIZED
Please provide proper credentials.

$ curl -H "Authorization: Basic YWRtaW46c2VjcmV0" -i http://example.com
HTTP/1.1 200 OK

デフォルトの場合,すべてのHTTP述語(メソッド)へのアクセスはすべての端点に限られ,API全体を効率的にロックする.

しかし、もしあなたの認証ロジックがより複雑で、いくつかのエンドポイントだけを保護したい場合、または使用されているエンドポイントによって異なる論理を適用したい場合、どうすればいいですか?認証クラスに論理を追加するだけでよく、以下のようになるかもしれません。

class MyBasicAuth(BasicAuth):
    def check_auth(self, username, password, allowed_roles, resource, method):
        if resource in ('zipcodes', 'countries'):
            # 'zipcodes' and 'countries' are public
            return True
        else:
            # all the other resources are secured
            return username == 'admin' and password == 'secret'

必要であれば、この方法はまた要求を受け入れることを許可します method 例えば許可されていることを考慮すると GET 編集者の検証を強制しながら各人に請求する (POST そして、 PUT そして、 PATCH そして、 DELETE )。

エンドレベル認証

♪the 1つのクラスはそれらをすべて結びつけています 上記で見た方法は、多くの用例に適用可能であるが、許可ロジックがより複雑になると、複雑で管理不可能なコードを招きやすく、セキュリティを処理する際に本当に望んでいるわけではない。

特定の認証クラスがあれば、選択されたサイトに自由に適用できるのではないでしょうか。このように,イヴ構造関数に渡される全局レベル認証クラス(上述したように)は,すべての端点(異なる許可論理を必要とする端点を除く)上でアクティブ状態である.あるいは選択することもできます not すべての端点を効率的に公開するグローバル認証クラスを提供するが,保護したい端点は除外する.このようなシステムを使用して、基本的な認証を使用していくつかのエンドポイントを保護し、トークンまたはHMAC認証を使用して他のエンドポイントを保護することも選択できます!

これは実際に可能であり、資源レベルを有効にするだけであることが証明されています authentication APIを定義する際に設定する domain それがそうです。

DOMAIN = {
    'people': {
        'authentication': MySuperCoolAuth,
        ...
        },
    'invoices': ...
    }

そのとおりです。♪the people エンドポイントはただいま使用しております MySuperCoolAuth クラスは認証を行い invoices エンドポイントは、提供される場合、汎用的なauthクラスを使用し、そうでなければ、それは一般にのみ開放されるであろう。

他の機能およびオプションを使用して、特に全局レベルの認証システムを使用する際に、認証クラスの複雑さを低減することもできます。復習しましょう。

グローバル端末セキュリティ

許可されたユーザのみが書き込み、編集、削除できる共通の読み取り専用APIが必要となる場合があります。ご利用いただけます PUBLIC_METHODS そして PUBLIC_ITEM_METHODS global settings それがそうです。以下の内容を追加します settings.py

PUBLIC_METHODS = ['GET']
PUBLIC_ITEM_METHODS = ['GET']

APIを実行します。POST,パッチ,削除は依然として制限されているが,GETはすべてのAPIエンドポイントで公開可能である. PUBLIC_METHODS リソースエンドポイントのことです /people そして同時に PUBLIC_ITEM_METHODS 個別のプロジェクトのことです /people/id それがそうです。

エンドポイントセキュリティをカスタマイズする.

もしあなたがただ特定の資源に対する公共読み取りアクセスを許可したいと仮定する。これは、リソースレベルで共通の方法を宣言し、APIを宣言することで実現することができます。 domain

DOMAIN = {
    'people': {
        'public_methods': ['GET'],
        'public_item_methods': ['GET'],
        },
    }

気をつけてください resource settings グローバル設定を上書きします。あなたはこれを利用することができてあなたに有利です。すべてのサイトへの読み出しアクセス権限を付与したいと仮定すると、唯一の例外は /invoices それがそうです。最初にすべてのエンドポイントの読み込みアクセス権限を開きます。

PUBLIC_METHODS = ['GET']
PUBLIC_ITEM_METHODS = ['GET']

次にプライベートエンドポイントを保護します:

DOMAIN = {
    'invoices': {
        'public_methods': [],
        'public_item_methods': [],
        }
    }

有効に使う invoices 限られた資源。

基本的な身分検証

♪the eve.auth.BasicAuth クラスは、基本認証(RFC 2617)を実現することを可能にする。カスタム認証を実現するためには,サブクラスに分類すべきである.

Bcryptを用いた基本認証

以下を用いてパスワードを符号化する. bcrypt いい考えですね。これは性能を犠牲にしているが、これが鍵となっている。遅いコードは暴力攻撃にうまく抵抗することを意味するからだ。より速い(ただし、あまり安全ではない)代替案については、以下のSHA 1/MACコードセグメントを参照されたい。

このスクリプトは、ユーザアカウントが格納されていると仮定する accounts MongoDB集合は,パスワードはbcryptハッシュ形式で格納される.明示的に公開されていない限り、すべてのAPIリソース/方法は保護されるであろう。

ご注意ください

インストールが必要になります py-bcrypt このことを効果的にすることができます

# -*- coding: utf-8 -*-

"""
    Auth-BCrypt
    ~~~~~~~~~~~

    Securing an Eve-powered API with Basic Authentication (RFC2617).

    You will need to install py-bcrypt: ``pip install py-bcrypt``

    This snippet by Nicola Iarocci can be used freely for anything you like.
    Consider it public domain.
"""

import bcrypt
from eve import Eve
from eve.auth import BasicAuth
from flask import current_app as app

class BCryptAuth(BasicAuth):
    def check_auth(self, username, password, allowed_roles, resource, method):
        # use Eve's own db driver; no additional connections/resources are used
        accounts = app.data.driver.db['accounts']
        account = accounts.find_one({'username': username})
        return account and \
            bcrypt.hashpw(password, account['password']) == account['password']


if __name__ == '__main__':
    app = Eve(auth=BCryptAuth)
    app.run()

SHA 1/HMACを用いた基本認証

このスクリプトは、ユーザアカウントが格納されていると仮定する accounts MongoDB集合,暗号はSHA 1/HMACハッシュ形式で格納される.明示的に公開されていない限り、すべてのAPIリソース/方法は保護されるであろう。

# -*- coding: utf-8 -*-

"""
    Auth-SHA1/HMAC
    ~~~~~~~~~~~~~~

    Securing an Eve-powered API with Basic Authentication (RFC2617).

    Since we are using werkzeug we don't need any extra import (werkzeug being
    one of Flask/Eve prerequisites).

    This snippet by Nicola Iarocci can be used freely for anything you like.
    Consider it public domain.
"""

from eve import Eve
from eve.auth import BasicAuth
from werkzeug.security import check_password_hash
from flask import current_app as app

class Sha1Auth(BasicAuth):
    def check_auth(self, username, password, allowed_roles, resource, method):
        # use Eve's own db driver; no additional connections/resources are used
        accounts = app.data.driver.db['accounts']
        account = accounts.find_one({'username': username})
        return account and \
            check_password_hash(account['password'], password)


if __name__ == '__main__':
    app = Eve(auth=Sha1Auth)
    app.run()

トークンによる認証

トークンに基づく認証は、基本的な認証の専用バージョンと見なすことができる。Authorizationヘッダタグは,ユーザ名としてauthトークンを含み,パスワードを含まない.

このスクリプトは、ユーザアカウントが格納されていると仮定する accounts MongoDB集合.それらが明示的に公開されない限り、すべてのAPIリソース/方法は保護されるであろう(いくつかの設定を修正することによって、1つまたは複数のリソースおよび/または方法を公衆に開放することができる(文書を参照)。

# -*- coding: utf-8 -*-

"""
    Auth-Token
    ~~~~~~~~~~

    Securing an Eve-powered API with Token based Authentication.

    This snippet by Nicola Iarocci can be used freely for anything you like.
    Consider it public domain.
"""

from eve import Eve
from eve.auth import TokenAuth
from flask import current_app as app

class TokenAuth(TokenAuth):
    def check_auth(self, token, allowed_roles, resource, method):
        """For the purpose of this example the implementation is as simple as
        possible. A 'real' token should probably contain a hash of the
        username/password combo, which should then be validated against the account
        data stored on the DB.
        """
        # use Eve's own db driver; no additional connections/resources are used
        accounts = app.data.driver.db['accounts']
        return accounts.find_one({'token': token})


if __name__ == '__main__':
    app = Eve(auth=TokenAuth)
    app.run()

HMACアイデンティティ検証

♪the eve.auth.HMACAuth クラスは,Amazon S 3のようなHMAC(Hash message Authentication Code,ハッシュメッセージ検証コード)の認証をカスタマイズすることを許可しており,これは基本的に非常に安全なカスタム認証スキームである. Authorization ヘディングです。

HMACアイデンティティ検証の動作原理

サーバは、ある種の帯域外技術を介してクライアントにユーザIDおよび鍵を提供する(例えば、サービスは、ユーザIDおよび鍵を含む電子メールをクライアントに送信する)。クライアントは、提供された鍵を使用してすべての要求に署名する。

クライアントが要求を送信したいとき、彼は完全な要求を構築し、次いで、鍵を使用してメッセージ·ボリューム全体(必要に応じて、いくつかのメッセージ·ヘッダも計算することができる)のハッシュを計算する。

次に、クライアントは、計算されたハッシュとそのユーザIDをAuthorizationヘッダのメッセージに追加する:

Authorization: johndoe:uCMfSzkjue+HSDygYB5aEg==

サービスに送信しますサービスは、メッセージヘッダからユーザIDを検索し、そのユーザの秘密鍵を自身のデータベースで検索する。次に、メッセージ本文(および選択されたヘッダ)のハッシュを鍵を使用して計算して、そのハッシュを生成する。クライアントが送信したハッシュがサーバによって計算されたハッシュと一致する場合、サーバは、メッセージが実際のクライアントによって送信されたことを知っており、いかなる方法でも変更されていない。

実際、唯一の厄介な部分は、ユーザと鍵を共有し、そのセキュリティを確保することである。それが、いくつかのサービスが、限られたライフサイクル内に共有鍵を生成することを可能にして、鍵を第三者に一時的にあなたの仕事を代表することができるようにする理由です。これはまた、秘密鍵が一般に帯域外チャネル(通常はウェブページ、または上述したように、電子メールまたは通常の古紙)を介して提供される理由でもある。

♪the eve.auth.HMACAuth クラスは訪問役もサポートしています。

HMAC例

次のコード片も examples/security folder of the Eve repository それがそうです。

from eve import Eve
from eve.auth import HMACAuth
from flask import current_app as app
from hashlib import sha1
import hmac


class HMACAuth(HMACAuth):
    def check_auth(self, userid, hmac_hash, headers, data, allowed_roles,
                   resource, method):
        # use Eve's own db driver; no additional connections/resources are
        # used
        accounts = app.data.driver.db['accounts']
        user = accounts.find_one({'userid': userid})
        if user:
            secret_key = user['secret_key']
        # in this implementation we only hash request data, ignoring the
        # headers.
        return user and \
            hmac.new(str(secret_key), str(data), sha1).hexdigest() == \
                hmac_hash


if __name__ == '__main__':
    app = Eve(auth=HMACAuth)
    app.run()

役割に基づくアクセス制御

上のコード片は意図的に無視しています allowed_roles パラメータこのパラメータを使用して、特定のロールも割り当てられた認証されたユーザにアクセス権限を制限することができます。

まず、新しいのをご利用いただけます ALLOWED_ROLES そして ALLOWED_ITEM_ROLES global settings (またはそれに対応する allowed_roles そして allowed_item_roles resource settings )。

ALLOWED_ROLES = ['admin']

そして、サブクラスは、上記のコードを十分に利用することで許可ロジックを実現します allowed_roles パラメータ

次のコード·セグメントは、ユーザアカウントが格納されていると仮定する accounts MongoDB集合,パスワードはSHA 1/HMACハッシュとして格納され,ユーザキャラクタは“Roles”配列に格納される.明示的に公開されていない限り、すべてのAPIリソース/方法は保護されるであろう。

# -*- coding: utf-8 -*-

"""
    Auth-SHA1/HMAC-Roles
    ~~~~~~~~~~~~~~~~~~~~

    Securing an Eve-powered API with Basic Authentication (RFC2617) and user
    roles.

    Since we are using werkzeug we don't need any extra import (werkzeug being
    one of Flask/Eve prerequisites).

    This snippet by Nicola Iarocci can be used freely for anything you like.
    Consider it public domain.
"""

from eve import Eve
from eve.auth import BasicAuth
from werkzeug.security import check_password_hash
from flask import current_app as app

class RolesAuth(BasicAuth):
    def check_auth(self, username, password, allowed_roles, resource, method):
        # use Eve's own db driver; no additional connections/resources are used
        accounts = app.data.driver.db['accounts']
        lookup = {'username': username}
        if allowed_roles:
            # only retrieve a user if his roles match ``allowed_roles``
            lookup['roles'] = {'$in': allowed_roles}
        account = accounts.find_one(lookup)
        return account and check_password_hash(account['password'], password)


if __name__ == '__main__':
    app = Eve(auth=RolesAuth)
    app.run()

ユーザ制限されたリソースアクセス

この機能を有効にすると、各格納された文書は、そのアカウントを作成することに関連付けられます。これにより、APIは、アカウント作成された文書をすべてのタイプの要求(読み出し、編集、削除、もちろん作成)に透過的に提供することができる。正常に動作するためには、ユーザ認証を有効にする必要がある。

グローバルレベルでは、以下のように設定することで、この機能を有効にすることができます AUTH_FIELD ローカル(終端点レベル)で設定することで auth_field それがそうです。これらの属性は、文書を作成するユーザIDを格納するためのフィールドの名前を定義する。例えば設定することで AUTH_FIELD 至る user_id 実際に(かつユーザに透明に)追加されています user_id フィールドは、各格納された文書に追加される。そして、これは、ユーザが記憶している文書を検索/編集/削除するために使用される。

しかしどのように設定するか auth_field 価値?呼び出して set_request_auth_value() 種類の方法。上のbcrypt認証例を修正しましょう。

 # -*- coding: utf-8 -*-

 """
     Auth-BCrypt
     ~~~~~~~~~~~

     Securing an Eve-powered API with Basic Authentication (RFC2617).

     You will need to install py-bcrypt: ``pip install py-bcrypt``

     This snippet by Nicola Iarocci can be used freely for anything you like.
     Consider it public domain.
 """

 import bcrypt
 from eve import Eve
 from eve.auth import BasicAuth


 class BCryptAuth(BasicAuth):
     def check_auth(self, username, password, allowed_roles, resource, method):
         # use Eve's own db driver; no additional connections/resources are used
         accounts = app.data.driver.db['accounts']
         account = accounts.find_one({'username': username})
         # set 'auth_field' value to the account's ObjectId
         # (instead of _id, you might want to use ID_FIELD)
         if account and '_id' in account:
             self.set_request_auth_value(account['_id'])
         return account and \
             bcrypt.hashpw(password, account['password']) == account['password']


 if __name__ == '__main__':
     app = Eve(auth=BCryptAuth)
     app.run()

認証ドライブのデータベースアクセス

カスタム認証クラスは、アクティビティ要求にサービスを提供する際に使用すべきデータベースを設定することもできる。

通常、API全体のために単一のデータベースを使用するか、設定することで mongo_prefix 必要な値に設定します(参照 リソース/プロジェクト最終ノード )。

しかし、アクティブトークン、ユーザ、またはクライアントに基づいてターゲットデータベースを選択することを選択することができます。もしあなたの用例がユーザ専用のデータベースインスタンスを含むなら、これは便利です。あなたがすべきことは set_mongo_prefix() 要求に対して認証を行う際に使用する.

些細な例です

from eve.auth import BasicAuth

class MyBasicAuth(BasicAuth):
    def check_auth(self, username, password, allowed_roles, resource, method):
        if username == 'user1':
            self.set_mongo_prefix('MONGO1')
        elif username == 'user2':
            self.set_mongo_prefix('MONGO2')
        else:
            # serve all other users from the default db.
            self.set_mongo_prefix(None)
        return username is not None and password == 'secret'

app = Eve(auth=MyBasicAuth)
app.run()

以上のコースでサービスをさせていただきます user1 データベースからのデータを使用して、設定されたプレフィックスは MONGO1 はい。 settings.py それがそうです。同じことが起きています user2 そして MONGO2 一方、他のすべてのユーザはデフォルトデータベースサービスを使用します。

設定された値から set_mongo_prefix() デフォルトレベルと終端ノードレベルに優先する mongo_prefix 設定時に,ここでは,終端ノードの最終データベース配置にかかわらず,つねに保持しているデータベースからこの2人のユーザにサービスを提供する場合が発生する.

OAuth 2統合

許可プロセスを完全に制御することができるので、OAuth 2とEveを統合することは容易です。このページに表示されているテーマを自由に読んで、転送してください Eve-OAuth2 これは例示的なプロジェクトです Flask-Sentinel OAuth 2を使用してAPIを保護する方法を示す.

ご注意ください

このページのコード片は examples/security folder of the Eve repository それがそうです。