web-dev-qa-db-ja.com

Flaskでの認証にAPIキーを使用する方法はありますか?

認証を追加したい小さなAPIがあります。 APIコンシューマー用のAPIキーを生成できるようにしたいのですが。次に、コンシューマは、リクエストリクエストにキーを含めることができます。

Flaskこのようなことを行うライブラリはありますか?またはそれを行うための典型的な方法はありますか?私は検索を実行しましたが、実際に思いついたのは this でした。あまり深く掘り下げていませんライブラリがある場合は探しています.

38
NickAldwin

認証キーの場合、ランダムな値を作成し、その値をデータベースに保存します。 random()は、このようなものには不十分なエントロピーを提供するため、os.urandom()を使用します。

あなたが投稿したリンクは、デコレータ関数で物事を処理する方法の非常に良い例を持っています。デコレータ関数で、リクエストにappkey値が設定されていることを確認し、それがデータベースで有効であることを確認してから、関数を返します。 appkeyが無効な場合は、raise AuthenticationError("Invalid appkey")で完了です。

リンクした例は少し混乱しています。私は 関数デコレータのチェーンを作成する方法? のデモンストレーションが好きです。

def checkAppKey(fn):
    def inner(*args, **kwargs): #appkey should be in kwargs
        try:
            AppKey.get(appkey)
        except KeyError:
            raise AuthenticationError("Invalid appkey")
            #Whatever other errors can raise up such as db inaccessible
        #We were able to access that API key, so pass onward.
        #If you know nothing else will use the appkey after this, you can unset it.
        return fn(*args, **kwargs)
    return inner
13
Jeff Ferland

これは私にとってかなりうまくいったhashlibを使用する関数です:

def generate_hash_key():
    """
    @return: A hashkey for use to authenticate agains the API.
    """
    return base64.b64encode(hashlib.sha256(str(random.getrandbits(256))).digest(),
                            random.choice(['rA', 'aZ', 'gQ', 'hH', 'hG', 'aR', 'DD'])).rstrip('==')

これをアプリに実装するための可能な解決策は、保護する各ルートにデコレータを適用することです。

例:

def get_apiauth_object_by_key(key):
    """
    Query the datastorage for an API key.
    @param ip: ip address
    @return: apiauth sqlachemy object.
    """
    return model.APIAuth.query.filter_by(key=key).first()

def match_api_keys(key, ip):
    """
   Match API keys and discard ip
   @param key: API key from request
   @param ip: remote Host IP to match the key.
   @return: boolean
   """
   if key is None or ip is None:
      return False
   api_key = get_apiauth_object_by_key(key)
   if api_key is None:
      return False
   Elif api_key.ip == "0.0.0.0":   # 0.0.0.0 means all IPs.
      return True
   Elif api_key.key == key and api_key.ip == ip:
      return True
   return False

def require_app_key(f):
   """
   @param f: flask function
   @return: decorator, return the wrapped function or abort json object.
   """

   @wraps(f)
   def decorated(*args, **kwargs):
      if match_api_keys(request.args.get('key'), request.remote_addr):
         return f(*args, **kwargs)
      else:
         with log_to_file:
            log.warning("Unauthorized address trying to use API: " + request.remote_addr)
         abort(401)
      return decorated

そして、次のようにデコレータを使用できます。

@require_app_key
def delete_cake(version, cake_id):
   """
   Controller for API Function that gets a cake by ID
   @param cake_id: cake id
   @return: Response and HTTP code
   """

この例では、SQLAlchemyを使用してデータベースにキーを格納します(SQLiteを使用できます)。

ここで実装を確認できます: https://github.com/haukurk/flask-restapi-recipe

8

APIキーを生成する「典型的な」方法は、UUIDを作成することです(通常、ユーザー情報のサブセットのサブセットのmd5ハッシュ+ランダムな情報(現在時刻など)を作成することによって)。

ただし、すべてのAPIキーはUUIDでなければなりません。 md5によって作成された16進数のハッシュはこの要件を満たしていますが、他の方法も確かにあります。

ユーザーのキーを作成したら、それをユーザー情報の一部としてデータベースに保存し、キー(通常はCookieに保存)がユーザーのキーと一致することを確認します。この実際のメカニズムは、リンク先のページに(ある程度)記述されています。

2
jeffknupp