web-dev-qa-db-ja.com

フラスコ:フロントエンドとバックエンドサービスをブリッジしてAPI認証をレンダリングする方法は?

flask-restplus で、最小限のflask APIのAPI認証ビューをレンダリングします。ここで、サーバーにリクエストを行うと、最初のAPIがポップします。 API呼び出しを使用する前にカスタマイズされたトークン値を提供するようユーザーに要求するための保護ビューを作成しました。API関数を使用する前にAPI認証ポップビューを作成するためのソリューションを考えましたが、それを正しく取得できませんでした。私のコードはスムーズに動作しますか?アイデアはありますか?

完全な実装での現在の試み

これは、このタスクを実行するための私の実装の部分的なコードです。

from functools import wraps
import requests, json, psycopg2, datetime
from time import time
from flask import Flask, request
from flask_sqlalchemy import SQLAlchemy
from flask_restplus import Resource, Api, abort, fields, inputs, reqparse
from itsdangerous import SignatureExpired, JSONWebSignatureSerializer, BadSignature


class AuthenticationToken:
    def __init__(self, secret_key, expires_in):
        self.secret_key = secret_key
        self.expires_in = expires_in
        self.serializer = JSONWebSignatureSerializer(secret_key)

    def generate_token(self, username):
        info = {
            'username': username,
            'creation_time': time()
        }

        token = self.serializer.dumps(info)
        return token.decode()

    def validate_token(self, token):
        info = self.serializer.loads(token.encode())

        if time() - info['creation_time'] > self.expires_in:
            raise SignatureExpired("The Token has been expired; get a new token")

        return info['username']


SECRET_KEY = "f4b58245-6fd4-4bce-a8a4-27ca37370a3c"
expires_in = 600
auth = AuthenticationToken(SECRET_KEY, expires_in)

db = SQLAlchemy(app)

API認証用にほぼすべてをコード化しましたが、希望する出力で期待した認証ポップビューを取得できませんでした。

更新:サーバーエンドポイントでの出力

私が試したときhttp://127.0.0.1:5000/tokenサーバーエンドポイントでNot Foundエラー。どうすれば希望の出力を取得できますか?何か案が?

APIへのアクセスにトークンが必要なAPI保護ビューを取得するにはどうすればよいですか。現在、エラーが発生し、目的の出力を取得できなかったため、SOコミュニティがこれを支援してくれることを願っています。

望ましい出力

サーバーエンドポイントでAPI呼び出しを使用する前に、テストAPIの保護ビューをレンダリングしたいと思います。以下は、取得したいモックアップAPI承認ビューです。

enter image description here

pythonフラスコ、flask安らぎ?考えて?

5

私はあなたが何をしているのかを理解し、@ B--rian、@ Matt L.が前述したように、SOコミュニティがすべてのコードベースを支援するのは一発の仕事ではありません。しかし、これは私がやったことであり、私はあなたがいくつかの苦痛であなたの仕事をどのように終えることができるかをあなたに案内します。

このタスクをいくつかのステップに分割することで解決できますが、このステップを回避して、ネストをもう1つ投稿します。

from functools import wraps
from time import time
from flask import Flask
from flask import request
from flask_restplus import Resource, Api
from flask_restplus import abort
from flask_restplus import fields
from flask_restplus import inputs
from flask_restplus import reqparse
from psycopg2.extensions import AsIs
import psycopg2, datetime, requests, json
from itsdangerous import SignatureExpired, JSONWebSignatureSerializer, BadSignature

'''
## to get API security key, to do:
import uuid
print(str(uuid.uuid4()))
'''

class AuthenticationToken(object):
    def __init__(self, secret_key, expires_in):
        self.secret_key = secret_key
        self.expires_in = expires_in
        self.serializer = JSONWebSignatureSerializer(secret_key)

    def generate_token(self, username):
        info = {
            'username': username,
            'creation_time': time()
        }
        token = self.serializer.dumps(info)
        return token.decode()

    def validate_token(self, token):
        info = self.serializer.loads(token.encode())

        if time() - info['creation_time'] > self.expires_in:
            raise SignatureExpired("The Token has been expired; get a new token")

        return info['username']

SECRET_KEY = "f4b58245-6fd4-4bce-a8a4-27ca37370a3c"
expires_in = 600
auth = AuthenticationToken(SECRET_KEY, expires_in)

app = Flask(__name__)
api = Api(app,authorizations={
                'API-KEY': {
                    'type': 'apiKey',
                    'in': 'header',
                    'name': 'AUTH-TOKEN'
                }
            },
          security='API-KEY',
          default="API AUTH TOKEN", 
          title="immunoMatch RESTful API", 
          description="Immunomatch ED API Authentication View") 

db = psycopg2.connect(database='test_db', user='postgres', password='password', Host='localhost', port="5432")

def requires_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):

        token = request.headers.get('AUTH-TOKEN')
        if not token:
            abort(401, 'Authentication token is missing')

        try:
            user = auth.validate_token(token)
        except SignatureExpired as e:
            abort(401, e.message)
        except BadSignature as e:
            abort(401, e.message)

        return f(*args, **kwargs)
    return decorated

credential_model = api.model('credential', {
    'username': fields.String(required=True),
    'password': fields.String(required=True)
})

credential_parser = reqparse.RequestParser()
credential_parser.add_argument('username', type=str)
credential_parser.add_argument('password', type=str)

@api.route('/token')
class Token(Resource):
    @api.expect(credential_parser, validate=True)
    def get(self):
        args = credential_parser.parse_args()
        username = args.get('username')
        password = args.get('password')
        cursor = db.cursor()
        cursor.execute('SELECT * FROM public.authorized_user_table')
        user = cursor.fetchone()

        if username != user[1]:
            api.abort(404, "Username: {} doesn't exist".format(username))
        if password != user[2]:
            api.abort(401, "Wrong password")
        return {"token": auth.generate_token(username)}

if __name__ == '__main__':
    db = psycopg2.connect(database='test_db', user='postgres', password='password', Host='localhost', port="5432")
    app.run(debug=True)

@ B--rian、@ Matt Lが彼らの投稿で述べたものを消化することをお勧めします、@ Matt Lはあなたが考えるべき価値のある何かを指摘したと思います。でも、残りがわかったらすぐに戻ってきます。

1
Jared

コメントが示すように、この質問に答えるために誰でも共有できる単純なコードスニペットはありません。あなたは基本的に、API資格情報を認証するためにデータベースをFlaskアプリにアタッチする方法について、5つのパートからなるブログを求めています。私はそれがこのように見えないことを知っていますが、あなたの質問あるトピックから次のトピックへとカスケードします。Flask Mega Tutorial Part IV Databases and Part V User Logins 。これらのチュートリアルは、次のように、コードが欠落しているように見える基本的な概念をカバーしています。

  1. SQLalchemy を使用してデータベースモデルを定義する
  2. DBでの基本許可テーブルの定義
  3. 暗号化を使用して、認証トークンをデータベースから削除できないようにする
  4. 認証テーブルから期限切れのトークンをフラッシュする
  5. Flask-Githubのgithub-callbackの例 または Flask-Login's login_requiredデコレータなど、事前に構築されたメソッドを使用して承認を検証する
  6. Flask-SQLalchemyのcreate_dbを使用してモデルからデータベースを構築する
  7. Flask-SQLalchemyのdb.sessionを使用してデータベースからデータを設定/取得する

それが価値があるものについては、私は本当にFlask Mega-Tutorialが役立つだろうと思います。

更新:これは 最小限の例 であり、辞書をおもちゃのデータベースとして使用しています。この例に関するいくつかのこと...

  1. Main.pyを実行して http://127.0.0.1:5000/token?username=admin&password=somepassword にアクセスすると、動作するgetの例が表示されます

  2. http://127.0.0.1:50 にアクセスし、「hello_world」、「投稿」、「試してみる」の順にクリックすると、ユーザー名とパスワードを入力できます。そしてそれらはモックデータベースに追加されます。

  3. ユーザー名とパスワードを追加した後、角かっこをその新しいユーザー名とパスワードに置き換える以外は http://127.0.0.1:5000/token?username= []&password = [] にアクセスできます。サーバーをシャットダウンすると、ユーザー辞書は更新されるだけなので、ユーザー名とパスワードは保存されません。

うまくいけば、これがすべて役に立ちます...このようにアプリを編集すると、ユーザー名とパスワードの認証に関連しない問題のデバッグが容易になります。

2
Matt L.

私があなたを正しく理解しているなら、あなたは JWT承認 のようなトークンベースの実装を実装したいと思います。

JWT全般

JWTの概要は docs.nginx.com> JWT authorization にまとめられています。

JWTは、OpenID Connect標準のユーザー情報のデータ形式です。これは、OAuth 2.0プロトコルの上にある標準のIDレイヤーです。APIおよびマイクロサービスのデプロイヤーも、そのためにJWT標準に目を向けています。シンプルさと柔軟性:JWT認証では、クライアントがJSON Web Tokenを提供し、トークンがローカルキーファイルまたはリモートサービスに対して検証されます。

必ずしもWebサーバーレベルでJWTを実行する必要はありませんが、データ(エンドポイント)とセキュリティを適切に分割するために、通常はWebサーバーレベルで認証を行うことを好みます。

次に、フラスコを使用したJWTに焦点を当てましょう。 blog.teclacode.com は、ワークフローを上手に要約しています[私によるコメント]:

  1. ユーザーはユーザー名とパスワードを提供します[異常なエンドポイントに]

[次の3つのステップは、その異常なエンドポイント内で発生します]。

  1. Flaskアプリ内で正しいことを確認します
  2. ユーザーのIDを含むJWTを生成します。
  3. それをユーザーに送信します。
  4. ユーザーがアプリケーションにリクエストを送信するたびに、以前に生成したJWTを送信する必要があります。

あなたの課題はステップ1から4にまたがっていると思います。ステップ5は、すでに実装したようです。これは、セキュリティ保護されていないエンドポイントplusです。 、必須のPOSTパラメータtoken。有効なトークンが提供されると、これらのエンドポイントはクライアントにデータを返します。つまり、通常の各エンドポイントは、指定されたトークンを検証する関数を呼び出します。この理解は正しいですか?ステップ5はすでに機能していますか?

私はPythonでJWTを実装したことはありませんが、 名前にJWTが含まれているパッケージをすばやく検索 構成する必要がある「すぐに」使用できるトークンジェネレーターがたくさんあるという印象を与えます。

コードに飛び込む

コードに関するいくつかの質問:

  1. 本当に秘密鍵をコード内にハードコーディングしますか?すべてのGITコミットなどでキーが公開されるため、これは重大なセキュリティ上の欠陥です。
  2. 一部のファイルには全文検索を妨げる構文エラーがあるため、GITのコード全体にアクセスするのは簡単ではありません。エラーメッセージは次のとおりです。

    エラーが修正されれば、そのファイルを美しく検索可能にすることができます。

  3. どこでどのようにuser_db定義されていますか?あなたはコメントでそれを述べました、しかし、私はそれを他の場所で見つけることができません。あなたの質問にこれに関する段落があると役に立ちます。
  4. http://127.0.0.1:5000/tokenは、トークンを提供するエンドポイントですが、現在の形式の質問では、エンドポイント/tokenが実装されています。
0
B--rian