簡體   English   中英

flask:如何橋接前端與后端服務以呈現 api 身份驗證?

[英]flask: how to bridge front-end with back-end service to render api authentication?

In flask-restplus , I want to render API authentication view for my minimal flask API, where whenever when I make a request to the server, the first API should pop up a protective view for asking the user to provide customized token value before using API稱呼。 在使用 api function 之前,我想出了我的解決方案來制作 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 身份驗證編寫了所有代碼,但無法在我想要的 output 中獲得我期望的身份驗證彈出視圖。

更新:服務器端點的 output

當我在服務器端點嘗試http://127.0.0.1:5000/token時,出現Not Found錯誤。 我怎樣才能得到我想要的 output? 任何想法?

我想知道如何獲得需要令牌才能訪問 API 的 api 保護視圖。 目前,我有一個錯誤,無法得到我想要的 output,所以我希望SO社區能幫助我解決這個問題。

所需的 output

我想在服務器端點上使用 API 調用之前為測試 API 呈現保護視圖。 這是我想要獲得的模型 API 授權視圖:

在此處輸入圖像描述

如何使用 python flask、flask 來實現這一點? 任何想法? 謝謝

正如評論所暗示的那樣,沒有任何人可以分享任何簡單的代碼片段來回答這個問題。 您基本上是在要求一個由五部分組成的博客,介紹如何將數據庫附加到 Flask 應用程序以驗證 API 憑據。 我知道看起來不是這樣,但是您的問題確實從一個主題延伸到下一個主題。 我認為您最好的選擇是查看 Flask Mega Tutorial Part IV Databases and Part V User Logins 這些教程涵蓋了您的代碼似乎缺少的基本概念,如下所示:

  1. 使用SQLalchemy定義您的數據庫模型
  2. 在數據庫中定義基本授權表
  3. 使用加密,以便您的授權令牌無法從數據庫中提取
  4. 從 auth 表中刷新過期令牌
  5. 使用預構建的方法來驗證授權,例如Flask-Github 的 github-callback 示例Flask-Login 的login_required 裝飾器
  6. 使用flask-SQLalchemy的create_db yo從你的model構建數據庫
  7. 使用 flask-SQLalchemy 的 db.session 從數據庫設置/獲取數據

對於它的價值,我真的認為 Flask 超級教程會有所幫助。

更新:這是一個使用字典作為玩具數據庫的最小示例 關於這個例子的一些事情......

  1. 如果您將 main.py 和 go 運行到http://127.0.0.1:5000/token?username=admin&password=somepassword您將看到有效的 get 示例

  2. 如果你是 go 到http://127.0.0.1:5000 ,點擊“hello_world”,點擊“post”,然后點擊“try it out”,輸入用戶名和密碼即可模擬數據庫。

  3. 添加用戶名和密碼后,您可以 go 到http://127.0.0.1:5000/token?username=[]&password=[]除了用新的用戶名和密碼替換括號。 如果您關閉服務器,則不會保存用戶名和密碼,因為它只是在更新字典。

希望所有這些都對您有所幫助……一旦您像這樣編輯了應用程序,應該更容易調試與用戶名和密碼身份驗證無關的問題。

我知道你在做什么,上面提到的@B--rian,@Matt L., SO社區不會為所有代碼庫提供幫助,這不是一次性的任務。 但這就是我所做的,我會指導你如何用一些痛苦來完成你的任務。

我們可以嘗試通過分幾個步驟來解決這個任務,但是讓我們繞過這一步,我很快就會發布嵌套一個:

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 確實指出了一些值得你考慮的東西,他們的建議很好,只是沒有給出太多的編碼嘗試。 但是一旦我發現 rest,我會盡快回復你。

如果我理解正確,您希望實現類似於JWT 授權的基於令牌的實現。

JWT 一般

JWT 的全部內容在文檔中得到了很好的總結。nginx.com > Z1D1FADBD9150349C135781 授權

JWT 是 OpenID Connect 標准中的用戶信息數據格式,它是 OAuth 2.0 協議之上的標准身份層。 API 和微服務的部署者也開始轉向 JWT 標准,因為它的簡單性和靈活性。 通過 JWT 身份驗證,客戶端提供 JSON Web 令牌,該令牌將針對本地密鑰文件或遠程服務進行驗證。

您不一定必須在網絡服務器級別執行 JWT,但我通常更喜歡在 web 服務器級別進行身份驗證,以便很好地拆分數據(又名端點)和安全性。

現在讓我們關注 JWT 和 flask。 blog.teclacode.com很好地總結了工作流程 [我的評論]:

  1. 用戶提供他們的用戶名和密碼 [給一個非凡的端點]

[接下來的 3 個步驟發生在那個非凡的端點內]。

  1. 我們在 Flask 應用程序中驗證它們是正確的
  2. 我們生成一個包含用戶 ID 的 JWT。
  3. 我們將其發送給用戶。
  4. 每當用戶向我們的應用程序發出請求時,他們必須向我們發送我們之前生成的 JWT。

我猜你的挑戰跨越了第 1 步到第 4 步。第 5 步你似乎已經實現了:它是不安全的端點加上一個額外的、強制性的 POST-parameter token 一旦提供了有效的令牌,這些端點就會將數據返回給客戶端。 換句話說:每個普通端點都會調用一個 function 來驗證給定的令牌。 這種理解正確嗎? 第 5 步已經為您工作了嗎?

我從未使用 python 實現 JWT,但是快速搜索名稱中帶有 JWT 的軟件包給我的印象是,有許多即用型令牌生成器可供您“剛剛”配置。

深入了解您的代碼

關於您的代碼的幾個問題:

  1. 你真的想在你的代碼中硬編碼你的密鑰嗎? 這是一個重大的安全漏洞,因為您將在所有 GIT 提交等中公開密鑰。
  2. 您在 GIT 的整個代碼不容易訪問,因為某些文件中存在一些語法錯誤,會阻止全文搜索,錯誤消息顯示:

    如果某些錯誤得到糾正,我們可以使該文件美觀且可搜索。

  3. user_db在哪里以及如何定義? 您在評論中提到了這一點,但我在其他地方找不到。 在您的問題中有一段關於此的段落會很有幫助。
  4. 我猜想http://127.0.0.1:5000/token是一個提供令牌的端點,但我從當前形式的問題中不完全理解端點/token的實現位置。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM