Khaitan

Khaitan

1633745009

के साथ FastAPI सर्वर बनाएं और सुरक्षित करें Auth0

FastAPI की मूल बातें जानें, कैसे जल्दी से सर्वर सेट करें और Auth0 के साथ सुरक्षित समापन बिंदु।

FastAPI एक अपेक्षाकृत नया पायथन ढांचा है जो आपको बहुत जल्दी एप्लिकेशन बनाने में सक्षम बनाता है। यह ढांचा आपको अंतर्निहित मॉड्यूल के साथ एपीआई अनुरोध डेटा को मूल रूप से पढ़ने की अनुमति देता है और फ्लास्क का हल्का विकल्प है।

इस लेख में, हम FastAPIAuth0 का उपयोग करके , एक मूल API सेट अप करने, एक समापन बिंदु की सुरक्षा करने की सुविधाओं पर चर्चा करेंगे, और आप सीखेंगे कि आरंभ करना कितना आसान है।

आवश्यक शर्तें

FastAPI के साथ निर्माण शुरू करने से पहले , आपके पास Python और एक निःशुल्क Auth0 खाता होना चाहिए; आप यहां साइन अप कर सकते हैं3.8.2

यदि आपने वह पायथन संस्करण स्थापित किया है और आपका Auth0 खाता है, तो आप एक नया FastAPIएप्लिकेशन बना सकते हैं । शुरू करने के लिए, भीतर विकसित करने के लिए एक नई निर्देशिका बनाएं। इस उदाहरण के लिए, आप नाम की एक निर्देशिका और नामक एक सबफ़ोल्डर बनाएंगे ; यह सबफ़ोल्डर वह जगह है जहाँ आपका कोड रहेगा।fastapi-exampleapplication

में फ़ोल्डर, निम्न आदेश का उपयोग कर एक आभासी वातावरण बनाने:fastapi-example

python3 -m venv .env

यह एक आभासी वातावरण बनाता है, और यह निर्भरता को आपके कंप्यूटर के बाकी पुस्तकालयों से अलग करता है। दूसरे शब्दों में, आप पुस्तकालयों और निर्भरताओं के साथ वैश्विक नामस्थान को प्रदूषित नहीं करते हैं, जो अन्य पायथन परियोजनाओं को प्रभावित कर सकता है।

वर्चुअल वातावरण बनाने के बाद, आपको इसे सक्रिय करने की आवश्यकता है। यूनिक्स-आधारित ऑपरेटिंग सिस्टम के लिए, यहाँ कमांड है:

source .env/bin/activate

यदि आप किसी अन्य ऑपरेटिंग सिस्टम में हैं, तो आप इस दस्तावेज़ीकरण पृष्ठ पर इस बात की सूची पा सकते हैं कि आप किसी परिवेश को कैसे सक्रिय कर सकते हैं । अपने आभासी वातावरण को सक्रिय करने के बाद, आप उन पैकेजों को स्थापित कर सकते हैं जिनका आप उपयोग करने जा रहे हैं: FastAPI, uvicorn सर्वर, pyjwt , और अद्यतन pip:

pip install -U pip
pip install fastapi uvicorn 'pyjwt[crypto]'

FastAPI के साथ शुरुआत करें

अब जब सभी पुस्तकालय स्थापित हो गए हैं, तो आप फ़ोल्डर के अंदर एक फ़ाइल बना सकते हैं ; वहीं आपका एपीआई कोड रहेगा। वसीयत की सामग्री इस तरह दिखेगी:main.pyapplicationmain.py

"""main.py
Python FastAPI Auth0 integration example
"""
 
from fastapi import FastAPI
# Creates app instance
app = FastAPI()
 
 
@app.get("/api/public")
def public():
    """No access token required to access this route"""

    result = {
        "status": "success",
        "msg": ("Hello from a public endpoint! You don't need to be "
                "authenticated to see this.")
    }
    return result

आइए इसे तोड़ते हैं: - शुरू करने के लिए, आप FastAPIपुस्तकालय का आयात कर रहे हैं ; - फिर किसी ऑब्जेक्ट को इंस्टेंट करके अपना ऐप बनाना ; - उसके बाद, आप अनुरोधों को संभालने वाले मार्ग को परिभाषित करने के लिए उपयोग करते हैं ; - अंत में, आपके पास पथ संचालन फ़ंक्शन कहा जाता है , जो एक ऐसा फ़ंक्शन है जो हर बार उस मार्ग को कॉल करेगा, और यह स्वागत संदेश के साथ एक शब्दकोश देता है।FastAPI()@app.getGETpublic()

अब जब आपको अपना पहला एंडपॉइंट कोड मिल गया है, तो सर्वर को ऊपर और चलाने के लिए, प्रोजेक्ट की रूट डायरेक्टरी पर निम्न कमांड चलाएँ:

uvicorn application.main:app --reload

आपके सर्वर के चलने के साथ, आप या तो http://127.0.0.1:8000/docs पर जा सकते हैं और पहले एंडपॉइंट के लिए स्वचालित रूप से जेनरेट किए गए दस्तावेज़ों को देख सकते हैं जैसा कि नीचे दी गई छवि में दिखाया गया है:

FastAPI प्रलेखन पृष्ठ सार्वजनिक समापन बिंदु दिखा रहा है

या आप का उपयोग करके एक नई टर्मिनल विंडो में अपना पहला अनुरोध कर सकते हैं cURL। ध्यान रखें कि यदि आप ऑपरेटिंग सिस्टम के पुराने संस्करण पर विंडोज उपयोगकर्ता हैं, तो आपको निम्न आदेश चलाने से पहले कर्ल स्थापित करना होगा :

curl -X 'GET' \
  --url http://127.0.0.1:8000/api/public

और आपके द्वारा अभी-अभी किए गए अनुरोध के परिणामस्वरूप आपको एक JSON देखना चाहिए:

{
  "status": "success",
  "msg": "Hello from a public endpoint! You don't need to be authenticated to see this."
}

सादगी के लिए, आप cURLइस पोस्ट के बाकी हिस्सों के लिए उपयोग करने जा रहे हैं ।

एक निजी समापन बिंदु बनाएँ

अब जब एक बेस एपीआई सर्वर सेट हो गया है, तो आप अपनी फाइल में एक और एंडपॉइंट जोड़ देंगे । इस एप्लिकेशन में, आपके पास सभी के लिए एक मार्ग उपलब्ध होगा और एक ऐसा मार्ग जिसे केवल आप उस एक्सेस टोकन से एक्सेस कर सकते हैं जो आपको Auth0 से मिलेगा।main.pyGET /api/publicGET /api/private

अब आपको फाइल को अपडेट करने की जरूरत है । यहां बताया गया है कि आपको आयात अनुभाग में क्या बदलना होगा:main.py

  • सबसे पहले, आपको मॉड्यूल Dependsसे आयात करने की आवश्यकता है fastapi, जो कि FastAPI निर्भरता इंजेक्शन प्रणाली है;
  • फिर, आपको मॉड्यूल HTTPBearerसे कक्षा को आयात करने की भी आवश्यकता होगी , वाहक टोकन के साथ प्राधिकरण शीर्षलेखों के लिए एक अंतर्निहित सुरक्षा योजना;fastapi.security
  • आपको के आधार पर प्राधिकरण योजना बनानी होगी HTTPBearer। इसका उपयोग Bearerनिजी समापन बिंदु पर किए गए प्रत्येक अनुरोध में टोकन के साथ प्राधिकरण शीर्षलेख की उपस्थिति की गारंटी के लिए किया जाएगा ।

टोकन सूचित एपीआई कि टोकन का वाहक अधिकृत किया गया है API तक पहुंच और गुंजाइश है कि प्राधिकरण के दौरान प्रदान की गई थी द्वारा निर्दिष्ट विशिष्ट कार्रवाई करने के लिए।

आयातों को अद्यतन करने के अलावा, आपको निजी समापन बिंदु लागू करने की आवश्यकता है। अंत बिंदु को भी स्वीकार करेंगे अनुरोध, और यहाँ कोड क्या है अब के लिए दिखाई देता है:/api/privateGETmain.py

"""main.py
Python FastAPI Auth0 integration example
"""
 
from fastapi import Depends, FastAPI  # 👈 new imports
from fastapi.security import HTTPBearer  # 👈 new imports


# Scheme for the Authorization header
token_auth_scheme = HTTPBearer()  # 👈 new code
 
# Creates app instance
app = FastAPI()

@app.get("/api/public")
def public():
    """No access token required to access this route"""
 
    result = {
        "status": "success",
        "msg": ("Hello from a public endpoint! You don't need to be "
                "authenticated to see this.")
    }
    return result


# new code 👇
@app.get("/api/private")
def private(token: str = Depends(token_auth_scheme)):
    """A valid access token is required to access this route"""
 
    result = token.credentials

    return result

Dependsवर्ग प्रत्येक अनुरोध है कि किसी भी endpoint एक समारोह, वर्ग या उदाहरण के खिलाफ प्राप्त करता है के मूल्यांकन के लिए जिम्मेदार है। इस मामले में, यह HTTPBearerयोजना के खिलाफ अनुरोधों का मूल्यांकन करेगा जो एक वाहक टोकन के साथ प्राधिकरण शीर्षलेख के अनुरोध की जांच करेगा।

आप इस बारे में अधिक जानकारी प्राप्त कर सकते हैं कि FastAPI निर्भरता इंजेक्शन इसके दस्तावेज़ीकरण पर कैसे काम करता है

अब आपका निजी समापन बिंदु प्राप्त टोकन लौटाता है। यदि कोई टोकन प्रदान नहीं किया जाता है, तो यह 403 Forbiddenविवरण के साथ एक स्थिति कोड लौटाएगा, जिसमें कहा जाएगा कि आप हैं "Not authenticated"। चूँकि आपने --reloadअपना सर्वर चलाते समय ध्वज का उपयोग किया था, इसलिए आपको कमांड को फिर से चलाने की आवश्यकता नहीं है; uvicornहर बार जब आप अपनी फ़ाइलें सहेजते हैं तो परिवर्तन उठाएंगे और सर्वर को अपडेट करेंगे। अब समापन बिंदु से उसके व्यवहार की जांच करने का अनुरोध करें। सबसे पहले, एक प्राधिकरण शीर्षलेख पारित किए बिना अनुरोध करें :GET /api/private

curl -X 'GET' \
  --url 'http://127.0.0.1:8000/api/private'
# {"detail": "Not authenticated"}

और अब, यदि आप प्राधिकरण शीर्षलेख के साथ अनुरोध करते हैं, लेकिन टोकन मान के रूप में एक यादृच्छिक स्ट्रिंग के साथ, आपको परिणाम के रूप में समान यादृच्छिक मान देखना चाहिए:

curl -X 'GET' \
  --url 'http://127.0.0.1:8000/api/private' \
  --header 'Authorization: Bearer FastAPI is awesome'
# "FastAPI is awesome"

जैसा कि आप देख सकते हैं, आपका समापन बिंदु सुरक्षित नहीं है क्योंकि यह प्राधिकरण शीर्षलेख के मान के रूप में किसी भी स्ट्रिंग को स्वीकार करता है। यह है पर्याप्त नहीं एक प्राधिकरण हैडर प्राप्त करने के लिए; किसी को समापन बिंदु तक पहुंचने देने के लिए आपको वाहक टोकन के मूल्य को भी सत्यापित करना होगा । आइए उस व्यवहार को ठीक करें।

Auth0 एक API सेट करें

इससे पहले कि आप उस बिंदु पर पहुँचें जहाँ आप अपने समापन बिंदुओं में टोकन को मान्य करने के लिए तैयार हैं, आपको Auth0 में एक एपीआई सेट करने की आवश्यकता है । जब यह API सेट अप किया जाता है, तो आपको Auth0 के लिए आवश्यक कुछ जानकारी तक पहुंच प्राप्त होती है - एक ऑडियंस, क्लाइंट आईडी और क्लाइंट सीक्रेट।

आपको सर्वर के भीतर से उस जानकारी तक पहुंच की भी आवश्यकता है; यहीं से एक कॉन्फ़िगरेशन फ़ाइल चलन में आती है। आपको .configप्रोजेक्ट की जड़ पर कॉल की गई कॉन्फ़िगरेशन फ़ाइल बनाने की आवश्यकता होगी । यह वही है जो .configफ़ाइल नीचे दिखनी चाहिए। तदनुसार मूल्यों को अद्यतन करना याद रखें:

# .config
 
[AUTH0]
DOMAIN = your.domain.auth0.com
API_AUDIENCE = your.api.audience
ALGORITHMS = RS256
ISSUER = https://your.domain.auth0.com/

यह कॉन्फ़िगरेशन टोकन सत्यापन चरण में Auth0 कॉन्फ़िगरेशन सेटिंग्स के लिए जाँच की पहेली का पहला भाग है। पालन ​​​​करने के लिए एक और अच्छा नियम है कि अपनी कॉन्फ़िगरेशन फ़ाइलों को पर्यावरण चर के साथ स्रोत कोड में कभी भी प्रतिबद्ध न करें। ऐसा होने से रोकने के लिए, आपको .gitignoreप्रोजेक्ट के रूट में एक फ़ाइल बनानी चाहिए और .configफ़ाइल को एक प्रविष्टि के रूप में जोड़ना चाहिए :

# .gitignore
.config

JSON वेब टोकन (JWT) सत्यापन जोड़ें

आपके FastAPIसर्वर के पास अब एक मार्ग है, लेकिन यह अभी तक सुरक्षित नहीं है। यह केवल जांचता है कि क्या आपके पास अनुरोध में प्राधिकरण शीर्षलेख है, जिसका अर्थ है कि आप इस प्रक्रिया में एक चरण खो रहे हैं: आपको पहुंच टोकन को सत्यापित करने की आवश्यकता है। ऐसा करने के लिए, आपको एक ऐसी वस्तु बनाने की आवश्यकता है जो JWT को मान्य करने के लिए सभी चरणों को पूरा करे क्योंकि Auth0 के एक्सेस टोकन JWT हैं।GET /api/private

रूटिंग परिभाषा से जिम्मेदारियों को अलग करने के लिए, आपको सभी उपयोगिता कोड रखने के लिए फ़ोल्डर के अंदर नामक एक नई फ़ाइल बनानी चाहिए , जैसे एक्सेस टोकन को मान्य करना और कॉन्फ़िगरेशन जानकारी पढ़ना।utils.pyapplication

पायथन osपुस्तकालय, साथ ही PyJWTऔर configparserपुस्तकालयों को आयात करके प्रारंभ करें । ओएस पुस्तकालय आपको पर्यावरण चरों तक पहुंच प्रदान करता है। जेडब्ल्यूटी पुस्तकालय आपको जेडब्ल्यूटी की जांच और सत्यापन करने के लिए कार्य देता है। ConfigParserहमनाम पुस्तकालय से वर्ग अजगर में पाया विन्यास सेटिंग्स को पढ़ने के लिए एक तरीका प्रदान करता .configफ़ाइल आपको पहले बनाए गए। और आयात के बाद आपके पास पहली चीज है जिसे एक फ़ंक्शन कहा जाता है , जिसे आप नीचे देख सकते हैं:set_up()

"""utils.py
"""

import os
import jwt
from configparser import ConfigParser

 
def set_up():
    """Sets up configuration for the app"""

    env = os.getenv("ENV", ".config")

    if env == ".config":
        config = ConfigParser()
        config.read(".config")
        config = config["AUTH0"]
    else:
        config = {
            "DOMAIN": os.getenv("DOMAIN", "your.domain.com"),
            "API_AUDIENCE": os.getenv("API_AUDIENCE", "your.audience.com"),
            "ISSUER": os.getenv("ISSUER", "https://your.domain.com/"),
            "ALGORITHMS": os.getenv("ALGORITHMS", "RS256"),
        }
    return config

समारोह पढ़ने के लिए जिम्मेदार है फाइल और एक विन्यास उद्देश्य यह है कि एक शब्दकोश की तरह काम करता बनाने। चूंकि यह नमूना कोड पर्यावरण चर पर भी चलने के लिए तैयार है, डिफ़ॉल्ट रूप से फ़ंक्शन फ़ाइल को पढ़ने का प्रयास करेगा । आप पर्यावरण चर को किसी अन्य मान पर सेट करके इस व्यवहार को बदल सकते हैं, इस मामले में उपरोक्त खंड के तहत आप देख सकते हैं सभी पर्यावरण चर को पढ़कर एक शब्दकोश बनाया जाएगा ।set_up().configset_up().configENVelse

पहेली का अगला भाग वह है जहाँ जादू होता है। आप VerifyTokenJWT टोकन सत्यापन को संभालने के लिए एक वर्ग बनाएंगे :

# paste the code 👇 after the set_up() function in the utils.py file
class VerifyToken():
    """Does all the token verification using PyJWT"""

    def __init__(self, token):
        self.token = token
        self.config = set_up()

        # This gets the JWKS from a given URL and does processing so you can
        # use any of the keys available
        jwks_url = f'https://{self.config["DOMAIN"]}/.well-known/jwks.json'
        self.jwks_client = jwt.PyJWKClient(jwks_url)

    def verify(self):
        # This gets the 'kid' from the passed token
        try:
            self.signing_key = self.jwks_client.get_signing_key_from_jwt(
                self.token
            ).key
        except jwt.exceptions.PyJWKClientError as error:
            return {"status": "error", "msg": error.__str__()}
        except jwt.exceptions.DecodeError as error:
            return {"status": "error", "msg": error.__str__()}

        try:
            payload = jwt.decode(
                self.token,
                self.signing_key,
                algorithms=self.config["ALGORITHMS"],
                audience=self.config["API_AUDIENCE"],
                issuer=self.config["ISSUER"],
            )
        except Exception as e:
            return {"status": "error", "message": str(e)}

        return payload

आइए यहां दिए गए चरणों को समझने के लिए इस वर्ग को तोड़ें:

  1. सबसे पहले, आपके पास विधि है: __init__()
    1. यह विधि उस tokenपैरामीटर को निर्दिष्ट करने के लिए ज़िम्मेदार है जिसकी VerifyTokenकक्षा को आवश्यकता है;
    2. यह उस कॉन्फ़िगरेशन को बनाने के लिए फ़ंक्शन भी चलाता है जिसकी कक्षा को आवश्यकता होगी;set_up()
    3. और अंत में, यह पैकेज से JWKSका उपयोग करके फ़ाइल के लिए पथ सेट करता है । एक JSON वेब कुंजी सेट, या संक्षेप में JWKS में एक टोकन हस्ताक्षर को मान्य करने और यह सुनिश्चित करने के लिए आवश्यक जानकारी होती है कि यह एक वैध टोकन है। क्योंकि Auth0 OAuth 2.0 को लागू करता है, इसमें एक "प्रसिद्ध" समापन बिंदु है जिसे आप कॉल कर सकते हैं और टोकन और उसके गुणों को मान्य करने के लिए उपयोग किए जाने वाले अतिरिक्त मेटाडेटा प्राप्त कर सकते हैं।PyJWKClientPyJWT
  2. दूसरा, आपके पास विधि है: verify()
    1. kidटोकन हस्ताक्षर को सत्यापित करने के लिए JWKS से उपयोग की गई कुंजी को हथियाने के लिए यह विधि कुंजी आईडी ( टोकन हेडर में मौजूद दावा) का उपयोग करती है। यदि यह चरण किसी भी संभावित त्रुटि से विफल हो जाता है, तो त्रुटि संदेश वापस आ जाता है;
    2. फिर, विधि अब तक एकत्रित जानकारी का उपयोग करके जेडब्ल्यूटी को डीकोड करने का प्रयास करती है। त्रुटियों के मामले में, यह त्रुटि संदेश देता है। सफल होने पर, टोकन पेलोड वापस कर दिया जाता है।

आइए देखें कि आगे के अनुभाग में हमारे निजी समापन बिंदु में कोड के इस टुकड़े का उपयोग कैसे करें।

Auth0 एक्सेस टोकन की पुष्टि करें

अंतिम पहेली टुकड़ा उस वर्ग को आयात करना है जिसे आपने अभी फ़ाइल में बनाया है और इसे एंडपॉइंट में उपयोग करें । यहां आपको बदलने की आवश्यकता है:utils.pyGET /api/private

  1. के लिए आयात खंड जोड़ने के लिए आयात अनुभाग को अपडेट करें VerifyToken, फिर अपने समापन बिंदु पर जाएं; आपको Responseकक्षा और statusवस्तु को आयात करने की भी आवश्यकता होगी fastapiताकि आप किसी त्रुटि के मामले में विस्तृत प्रतिक्रिया दे सकें;
  2. फिर, आपको VerifyTokenकक्षा को टोकन पास करके और विधि का परिणाम एक त्रुटि है या नहीं, इसकी जाँच करके समापन बिंदु को समायोजित करने की आवश्यकता होगी ।verify()

यहां बताया गया है कि उपरोक्त सभी परिवर्तनों के साथ आपकी फ़ाइल कैसी दिखनी चाहिए:main.py

"""main.py
Python FastAPI Auth0 integration example
"""
 
from fastapi import Depends, FastAPI, Response, status  # 👈 new imports
from fastapi.security import HTTPBearer
 
from .utils import VerifyToken  # 👈 new import

# Scheme for the Authorization header
token_auth_scheme = HTTPBearer()
 
# Creates app instance
app = FastAPI()
 
 
@app.get("/api/public")
def public():
   """No access token required to access this route"""
 
   result = {
       "status": "success",
       "msg": ("Hello from a public endpoint! You don't need to be "
               "authenticated to see this.")
   }
   return result
 
 
@app.get("/api/private")
def private(response: Response, token: str = Depends(token_auth_scheme)):  # 👈 updated code
    """A valid access token is required to access this route"""
 
    result = VerifyToken(token.credentials).verify()  # 👈 updated code

    # 👇 new code
    if result.get("status"):
       response.status_code = status.HTTP_400_BAD_REQUEST
       return result
    # 👆 new code
 
    return result

इस अपडेट के साथ, आप अपने सुरक्षित एंडपॉइंट को ठीक से सेट कर रहे हैं और आपको आवश्यक एक्सेस टोकन के लिए सभी सत्यापन चरण कर रहे हैं। मैं

भले ही आपने अपने सर्वर को --reloadध्वज के साथ शुरू किया क्योंकि आपको यह सुनिश्चित करने की आवश्यकता है कि कॉन्फ़िगरेशन लोड हो गया है, यह uvicornप्रक्रिया को समाप्त करने और फिर सर्वर को पुनरारंभ करने का एक अच्छा समय है । यह .configफ़ाइल या पर्यावरण चर से कॉन्फ़िगरेशन पैरामीटर के साथ आपके एपीआई की उचित कार्यक्षमता की गारंटी देगा ।

इससे पहले कि आप FastAPIसर्वर में संरक्षित एंडपॉइंट के लिए अनुरोध कर सकें , आपको Auth0 से एक्सेस टोकन की आवश्यकता है। आप इसे Testअपने API के टैब में Auth0 डैशबोर्ड से कॉपी करके प्राप्त कर सकते हैं ।

आप एक्सेस टोकन प्राप्त करने POSTके लिए Auth0 के एंडपॉइंट पर कर्ल अनुरोध का उपयोग कर सकते हैं, और आप इस अनुरोध को Auth0 डैशबोर्ड में अपने API के टैब से कॉपी कर सकते हैं । कर्ल अनुरोध इस तरह दिखेगा; आवश्यकतानुसार मानों को भरना याद रखें:oauth/tokenTest

curl -X 'POST' \
--url 'https://<YOUR DOMAIN HERE>/oauth/token' \
 --header 'content-type: application/x-www-form-urlencoded' \
 --data grant_type=client_credentials \
 --data 'client_id=<YOUR CLIENT ID HERE>' \
 --data client_secret=<YOUR CLIENT SECRET HERE> \
 --data audience=<YOUR AUDIENCE HERE>

कमांड लाइन में, आपको अपने वाहक टोकन वाली एक प्रतिक्रिया दिखाई देनी चाहिए, जैसे कि:​

{
    "access_token": "<YOUR_BEARER_TOKEN>",
    "expires_in": 86400,
    "token_type": "Bearer"
}

अब आप निजी समापन बिंदु तक पहुँचने के लिए इस एक्सेस टोकन का उपयोग कर सकते हैं:

curl -X 'GET' \
--url 'http://127.0.0.1:8000/api/private' \
--header  'Authorization: Bearer <YOUR_BEARER_TOKEN>'

यदि अनुरोध सफल होता है, तो सर्वर एक्सेस टोकन के पेलोड को वापस भेज देगा:

{
    "iss": "https://<YOUR_DOMAIN>/",
    "sub": "iojadoijawdioWDasdijasoid@clients",
    "aud": "http://<YOUR_AUDIENCE>",
    "iat": 1630341660,
    "exp": 1630428060,
    "azp": "ADKASDawdopjaodjwopdAWDdsd",
    "gty": "client-credentials"
}

ध्यान रखें कि यदि सत्यापन विफल हो जाता है, तो आपको इसका विवरण देखना चाहिए कि क्या गलत हुआ।

और बस इतना ही - आपने निजी समापन बिंदु की सुरक्षा करना और उसकी सुरक्षा का परीक्षण करना समाप्त कर दिया है।

संक्षिप्त

आपने इस ब्लॉग पोस्ट में काफी कुछ सीखा। शुरू करने के लिए, आपने FastAPIदो समापन बिंदुओं को लागू करके मूल बातें सीखीं - एक सार्वजनिक, एक निजी। आपने देखा कि इन दोनों अंतिम बिंदुओं के लिए अनुरोध करना कितना आसान है। आपने एक सत्यापन वर्ग बनाया और देखा कि कैसे PyJWT आपको Auth0 एक्सेस टोकन को मान्य करने में मदद करता है, और आपने सीखा कि JWKS क्या है।

आप Auth0 डैशबोर्ड में अपना API बनाने की प्रक्रिया से गुजरे हैं। आपने यह भी सीखा कि निर्भरता इंजेक्शन प्रणाली का लाभ उठाकर अपने एक अंतिम बिंदु को कैसे सुरक्षित किया जाए FastAPI आपको एकीकरण को लागू करने में मदद करने के लिए प्रदान करता है। और आपने यह सब बहुत जल्दी किया।

संक्षेप में, आपने सीखा है कि के साथ उठना और दौड़ना कितना आसान है FastAPI, साथ ही साथ अपने समापन बिंदुओं की सुरक्षा के लिए Auth0 का उपयोग कैसे करना है।

इस GitHub रेपो में , आपको आज बनाए गए सैंपल एप्लिकेशन का पूरा कोड मिलेगा। यदि आपके कोई प्रश्न हैं, तो उन्हें इस ब्लॉग पोस्ट के लिए सामुदायिक फ़ोरम थ्रेड में पूछें।

#python #auth0 #fastapi

What is GEEK

Buddha Community

के साथ FastAPI सर्वर बनाएं और सुरक्षित करें Auth0
Khaitan

Khaitan

1633745009

के साथ FastAPI सर्वर बनाएं और सुरक्षित करें Auth0

FastAPI की मूल बातें जानें, कैसे जल्दी से सर्वर सेट करें और Auth0 के साथ सुरक्षित समापन बिंदु।

FastAPI एक अपेक्षाकृत नया पायथन ढांचा है जो आपको बहुत जल्दी एप्लिकेशन बनाने में सक्षम बनाता है। यह ढांचा आपको अंतर्निहित मॉड्यूल के साथ एपीआई अनुरोध डेटा को मूल रूप से पढ़ने की अनुमति देता है और फ्लास्क का हल्का विकल्प है।

इस लेख में, हम FastAPIAuth0 का उपयोग करके , एक मूल API सेट अप करने, एक समापन बिंदु की सुरक्षा करने की सुविधाओं पर चर्चा करेंगे, और आप सीखेंगे कि आरंभ करना कितना आसान है।

आवश्यक शर्तें

FastAPI के साथ निर्माण शुरू करने से पहले , आपके पास Python और एक निःशुल्क Auth0 खाता होना चाहिए; आप यहां साइन अप कर सकते हैं3.8.2

यदि आपने वह पायथन संस्करण स्थापित किया है और आपका Auth0 खाता है, तो आप एक नया FastAPIएप्लिकेशन बना सकते हैं । शुरू करने के लिए, भीतर विकसित करने के लिए एक नई निर्देशिका बनाएं। इस उदाहरण के लिए, आप नाम की एक निर्देशिका और नामक एक सबफ़ोल्डर बनाएंगे ; यह सबफ़ोल्डर वह जगह है जहाँ आपका कोड रहेगा।fastapi-exampleapplication

में फ़ोल्डर, निम्न आदेश का उपयोग कर एक आभासी वातावरण बनाने:fastapi-example

python3 -m venv .env

यह एक आभासी वातावरण बनाता है, और यह निर्भरता को आपके कंप्यूटर के बाकी पुस्तकालयों से अलग करता है। दूसरे शब्दों में, आप पुस्तकालयों और निर्भरताओं के साथ वैश्विक नामस्थान को प्रदूषित नहीं करते हैं, जो अन्य पायथन परियोजनाओं को प्रभावित कर सकता है।

वर्चुअल वातावरण बनाने के बाद, आपको इसे सक्रिय करने की आवश्यकता है। यूनिक्स-आधारित ऑपरेटिंग सिस्टम के लिए, यहाँ कमांड है:

source .env/bin/activate

यदि आप किसी अन्य ऑपरेटिंग सिस्टम में हैं, तो आप इस दस्तावेज़ीकरण पृष्ठ पर इस बात की सूची पा सकते हैं कि आप किसी परिवेश को कैसे सक्रिय कर सकते हैं । अपने आभासी वातावरण को सक्रिय करने के बाद, आप उन पैकेजों को स्थापित कर सकते हैं जिनका आप उपयोग करने जा रहे हैं: FastAPI, uvicorn सर्वर, pyjwt , और अद्यतन pip:

pip install -U pip
pip install fastapi uvicorn 'pyjwt[crypto]'

FastAPI के साथ शुरुआत करें

अब जब सभी पुस्तकालय स्थापित हो गए हैं, तो आप फ़ोल्डर के अंदर एक फ़ाइल बना सकते हैं ; वहीं आपका एपीआई कोड रहेगा। वसीयत की सामग्री इस तरह दिखेगी:main.pyapplicationmain.py

"""main.py
Python FastAPI Auth0 integration example
"""
 
from fastapi import FastAPI
# Creates app instance
app = FastAPI()
 
 
@app.get("/api/public")
def public():
    """No access token required to access this route"""

    result = {
        "status": "success",
        "msg": ("Hello from a public endpoint! You don't need to be "
                "authenticated to see this.")
    }
    return result

आइए इसे तोड़ते हैं: - शुरू करने के लिए, आप FastAPIपुस्तकालय का आयात कर रहे हैं ; - फिर किसी ऑब्जेक्ट को इंस्टेंट करके अपना ऐप बनाना ; - उसके बाद, आप अनुरोधों को संभालने वाले मार्ग को परिभाषित करने के लिए उपयोग करते हैं ; - अंत में, आपके पास पथ संचालन फ़ंक्शन कहा जाता है , जो एक ऐसा फ़ंक्शन है जो हर बार उस मार्ग को कॉल करेगा, और यह स्वागत संदेश के साथ एक शब्दकोश देता है।FastAPI()@app.getGETpublic()

अब जब आपको अपना पहला एंडपॉइंट कोड मिल गया है, तो सर्वर को ऊपर और चलाने के लिए, प्रोजेक्ट की रूट डायरेक्टरी पर निम्न कमांड चलाएँ:

uvicorn application.main:app --reload

आपके सर्वर के चलने के साथ, आप या तो http://127.0.0.1:8000/docs पर जा सकते हैं और पहले एंडपॉइंट के लिए स्वचालित रूप से जेनरेट किए गए दस्तावेज़ों को देख सकते हैं जैसा कि नीचे दी गई छवि में दिखाया गया है:

FastAPI प्रलेखन पृष्ठ सार्वजनिक समापन बिंदु दिखा रहा है

या आप का उपयोग करके एक नई टर्मिनल विंडो में अपना पहला अनुरोध कर सकते हैं cURL। ध्यान रखें कि यदि आप ऑपरेटिंग सिस्टम के पुराने संस्करण पर विंडोज उपयोगकर्ता हैं, तो आपको निम्न आदेश चलाने से पहले कर्ल स्थापित करना होगा :

curl -X 'GET' \
  --url http://127.0.0.1:8000/api/public

और आपके द्वारा अभी-अभी किए गए अनुरोध के परिणामस्वरूप आपको एक JSON देखना चाहिए:

{
  "status": "success",
  "msg": "Hello from a public endpoint! You don't need to be authenticated to see this."
}

सादगी के लिए, आप cURLइस पोस्ट के बाकी हिस्सों के लिए उपयोग करने जा रहे हैं ।

एक निजी समापन बिंदु बनाएँ

अब जब एक बेस एपीआई सर्वर सेट हो गया है, तो आप अपनी फाइल में एक और एंडपॉइंट जोड़ देंगे । इस एप्लिकेशन में, आपके पास सभी के लिए एक मार्ग उपलब्ध होगा और एक ऐसा मार्ग जिसे केवल आप उस एक्सेस टोकन से एक्सेस कर सकते हैं जो आपको Auth0 से मिलेगा।main.pyGET /api/publicGET /api/private

अब आपको फाइल को अपडेट करने की जरूरत है । यहां बताया गया है कि आपको आयात अनुभाग में क्या बदलना होगा:main.py

  • सबसे पहले, आपको मॉड्यूल Dependsसे आयात करने की आवश्यकता है fastapi, जो कि FastAPI निर्भरता इंजेक्शन प्रणाली है;
  • फिर, आपको मॉड्यूल HTTPBearerसे कक्षा को आयात करने की भी आवश्यकता होगी , वाहक टोकन के साथ प्राधिकरण शीर्षलेखों के लिए एक अंतर्निहित सुरक्षा योजना;fastapi.security
  • आपको के आधार पर प्राधिकरण योजना बनानी होगी HTTPBearer। इसका उपयोग Bearerनिजी समापन बिंदु पर किए गए प्रत्येक अनुरोध में टोकन के साथ प्राधिकरण शीर्षलेख की उपस्थिति की गारंटी के लिए किया जाएगा ।

टोकन सूचित एपीआई कि टोकन का वाहक अधिकृत किया गया है API तक पहुंच और गुंजाइश है कि प्राधिकरण के दौरान प्रदान की गई थी द्वारा निर्दिष्ट विशिष्ट कार्रवाई करने के लिए।

आयातों को अद्यतन करने के अलावा, आपको निजी समापन बिंदु लागू करने की आवश्यकता है। अंत बिंदु को भी स्वीकार करेंगे अनुरोध, और यहाँ कोड क्या है अब के लिए दिखाई देता है:/api/privateGETmain.py

"""main.py
Python FastAPI Auth0 integration example
"""
 
from fastapi import Depends, FastAPI  # 👈 new imports
from fastapi.security import HTTPBearer  # 👈 new imports


# Scheme for the Authorization header
token_auth_scheme = HTTPBearer()  # 👈 new code
 
# Creates app instance
app = FastAPI()

@app.get("/api/public")
def public():
    """No access token required to access this route"""
 
    result = {
        "status": "success",
        "msg": ("Hello from a public endpoint! You don't need to be "
                "authenticated to see this.")
    }
    return result


# new code 👇
@app.get("/api/private")
def private(token: str = Depends(token_auth_scheme)):
    """A valid access token is required to access this route"""
 
    result = token.credentials

    return result

Dependsवर्ग प्रत्येक अनुरोध है कि किसी भी endpoint एक समारोह, वर्ग या उदाहरण के खिलाफ प्राप्त करता है के मूल्यांकन के लिए जिम्मेदार है। इस मामले में, यह HTTPBearerयोजना के खिलाफ अनुरोधों का मूल्यांकन करेगा जो एक वाहक टोकन के साथ प्राधिकरण शीर्षलेख के अनुरोध की जांच करेगा।

आप इस बारे में अधिक जानकारी प्राप्त कर सकते हैं कि FastAPI निर्भरता इंजेक्शन इसके दस्तावेज़ीकरण पर कैसे काम करता है

अब आपका निजी समापन बिंदु प्राप्त टोकन लौटाता है। यदि कोई टोकन प्रदान नहीं किया जाता है, तो यह 403 Forbiddenविवरण के साथ एक स्थिति कोड लौटाएगा, जिसमें कहा जाएगा कि आप हैं "Not authenticated"। चूँकि आपने --reloadअपना सर्वर चलाते समय ध्वज का उपयोग किया था, इसलिए आपको कमांड को फिर से चलाने की आवश्यकता नहीं है; uvicornहर बार जब आप अपनी फ़ाइलें सहेजते हैं तो परिवर्तन उठाएंगे और सर्वर को अपडेट करेंगे। अब समापन बिंदु से उसके व्यवहार की जांच करने का अनुरोध करें। सबसे पहले, एक प्राधिकरण शीर्षलेख पारित किए बिना अनुरोध करें :GET /api/private

curl -X 'GET' \
  --url 'http://127.0.0.1:8000/api/private'
# {"detail": "Not authenticated"}

और अब, यदि आप प्राधिकरण शीर्षलेख के साथ अनुरोध करते हैं, लेकिन टोकन मान के रूप में एक यादृच्छिक स्ट्रिंग के साथ, आपको परिणाम के रूप में समान यादृच्छिक मान देखना चाहिए:

curl -X 'GET' \
  --url 'http://127.0.0.1:8000/api/private' \
  --header 'Authorization: Bearer FastAPI is awesome'
# "FastAPI is awesome"

जैसा कि आप देख सकते हैं, आपका समापन बिंदु सुरक्षित नहीं है क्योंकि यह प्राधिकरण शीर्षलेख के मान के रूप में किसी भी स्ट्रिंग को स्वीकार करता है। यह है पर्याप्त नहीं एक प्राधिकरण हैडर प्राप्त करने के लिए; किसी को समापन बिंदु तक पहुंचने देने के लिए आपको वाहक टोकन के मूल्य को भी सत्यापित करना होगा । आइए उस व्यवहार को ठीक करें।

Auth0 एक API सेट करें

इससे पहले कि आप उस बिंदु पर पहुँचें जहाँ आप अपने समापन बिंदुओं में टोकन को मान्य करने के लिए तैयार हैं, आपको Auth0 में एक एपीआई सेट करने की आवश्यकता है । जब यह API सेट अप किया जाता है, तो आपको Auth0 के लिए आवश्यक कुछ जानकारी तक पहुंच प्राप्त होती है - एक ऑडियंस, क्लाइंट आईडी और क्लाइंट सीक्रेट।

आपको सर्वर के भीतर से उस जानकारी तक पहुंच की भी आवश्यकता है; यहीं से एक कॉन्फ़िगरेशन फ़ाइल चलन में आती है। आपको .configप्रोजेक्ट की जड़ पर कॉल की गई कॉन्फ़िगरेशन फ़ाइल बनाने की आवश्यकता होगी । यह वही है जो .configफ़ाइल नीचे दिखनी चाहिए। तदनुसार मूल्यों को अद्यतन करना याद रखें:

# .config
 
[AUTH0]
DOMAIN = your.domain.auth0.com
API_AUDIENCE = your.api.audience
ALGORITHMS = RS256
ISSUER = https://your.domain.auth0.com/

यह कॉन्फ़िगरेशन टोकन सत्यापन चरण में Auth0 कॉन्फ़िगरेशन सेटिंग्स के लिए जाँच की पहेली का पहला भाग है। पालन ​​​​करने के लिए एक और अच्छा नियम है कि अपनी कॉन्फ़िगरेशन फ़ाइलों को पर्यावरण चर के साथ स्रोत कोड में कभी भी प्रतिबद्ध न करें। ऐसा होने से रोकने के लिए, आपको .gitignoreप्रोजेक्ट के रूट में एक फ़ाइल बनानी चाहिए और .configफ़ाइल को एक प्रविष्टि के रूप में जोड़ना चाहिए :

# .gitignore
.config

JSON वेब टोकन (JWT) सत्यापन जोड़ें

आपके FastAPIसर्वर के पास अब एक मार्ग है, लेकिन यह अभी तक सुरक्षित नहीं है। यह केवल जांचता है कि क्या आपके पास अनुरोध में प्राधिकरण शीर्षलेख है, जिसका अर्थ है कि आप इस प्रक्रिया में एक चरण खो रहे हैं: आपको पहुंच टोकन को सत्यापित करने की आवश्यकता है। ऐसा करने के लिए, आपको एक ऐसी वस्तु बनाने की आवश्यकता है जो JWT को मान्य करने के लिए सभी चरणों को पूरा करे क्योंकि Auth0 के एक्सेस टोकन JWT हैं।GET /api/private

रूटिंग परिभाषा से जिम्मेदारियों को अलग करने के लिए, आपको सभी उपयोगिता कोड रखने के लिए फ़ोल्डर के अंदर नामक एक नई फ़ाइल बनानी चाहिए , जैसे एक्सेस टोकन को मान्य करना और कॉन्फ़िगरेशन जानकारी पढ़ना।utils.pyapplication

पायथन osपुस्तकालय, साथ ही PyJWTऔर configparserपुस्तकालयों को आयात करके प्रारंभ करें । ओएस पुस्तकालय आपको पर्यावरण चरों तक पहुंच प्रदान करता है। जेडब्ल्यूटी पुस्तकालय आपको जेडब्ल्यूटी की जांच और सत्यापन करने के लिए कार्य देता है। ConfigParserहमनाम पुस्तकालय से वर्ग अजगर में पाया विन्यास सेटिंग्स को पढ़ने के लिए एक तरीका प्रदान करता .configफ़ाइल आपको पहले बनाए गए। और आयात के बाद आपके पास पहली चीज है जिसे एक फ़ंक्शन कहा जाता है , जिसे आप नीचे देख सकते हैं:set_up()

"""utils.py
"""

import os
import jwt
from configparser import ConfigParser

 
def set_up():
    """Sets up configuration for the app"""

    env = os.getenv("ENV", ".config")

    if env == ".config":
        config = ConfigParser()
        config.read(".config")
        config = config["AUTH0"]
    else:
        config = {
            "DOMAIN": os.getenv("DOMAIN", "your.domain.com"),
            "API_AUDIENCE": os.getenv("API_AUDIENCE", "your.audience.com"),
            "ISSUER": os.getenv("ISSUER", "https://your.domain.com/"),
            "ALGORITHMS": os.getenv("ALGORITHMS", "RS256"),
        }
    return config

समारोह पढ़ने के लिए जिम्मेदार है फाइल और एक विन्यास उद्देश्य यह है कि एक शब्दकोश की तरह काम करता बनाने। चूंकि यह नमूना कोड पर्यावरण चर पर भी चलने के लिए तैयार है, डिफ़ॉल्ट रूप से फ़ंक्शन फ़ाइल को पढ़ने का प्रयास करेगा । आप पर्यावरण चर को किसी अन्य मान पर सेट करके इस व्यवहार को बदल सकते हैं, इस मामले में उपरोक्त खंड के तहत आप देख सकते हैं सभी पर्यावरण चर को पढ़कर एक शब्दकोश बनाया जाएगा ।set_up().configset_up().configENVelse

पहेली का अगला भाग वह है जहाँ जादू होता है। आप VerifyTokenJWT टोकन सत्यापन को संभालने के लिए एक वर्ग बनाएंगे :

# paste the code 👇 after the set_up() function in the utils.py file
class VerifyToken():
    """Does all the token verification using PyJWT"""

    def __init__(self, token):
        self.token = token
        self.config = set_up()

        # This gets the JWKS from a given URL and does processing so you can
        # use any of the keys available
        jwks_url = f'https://{self.config["DOMAIN"]}/.well-known/jwks.json'
        self.jwks_client = jwt.PyJWKClient(jwks_url)

    def verify(self):
        # This gets the 'kid' from the passed token
        try:
            self.signing_key = self.jwks_client.get_signing_key_from_jwt(
                self.token
            ).key
        except jwt.exceptions.PyJWKClientError as error:
            return {"status": "error", "msg": error.__str__()}
        except jwt.exceptions.DecodeError as error:
            return {"status": "error", "msg": error.__str__()}

        try:
            payload = jwt.decode(
                self.token,
                self.signing_key,
                algorithms=self.config["ALGORITHMS"],
                audience=self.config["API_AUDIENCE"],
                issuer=self.config["ISSUER"],
            )
        except Exception as e:
            return {"status": "error", "message": str(e)}

        return payload

आइए यहां दिए गए चरणों को समझने के लिए इस वर्ग को तोड़ें:

  1. सबसे पहले, आपके पास विधि है: __init__()
    1. यह विधि उस tokenपैरामीटर को निर्दिष्ट करने के लिए ज़िम्मेदार है जिसकी VerifyTokenकक्षा को आवश्यकता है;
    2. यह उस कॉन्फ़िगरेशन को बनाने के लिए फ़ंक्शन भी चलाता है जिसकी कक्षा को आवश्यकता होगी;set_up()
    3. और अंत में, यह पैकेज से JWKSका उपयोग करके फ़ाइल के लिए पथ सेट करता है । एक JSON वेब कुंजी सेट, या संक्षेप में JWKS में एक टोकन हस्ताक्षर को मान्य करने और यह सुनिश्चित करने के लिए आवश्यक जानकारी होती है कि यह एक वैध टोकन है। क्योंकि Auth0 OAuth 2.0 को लागू करता है, इसमें एक "प्रसिद्ध" समापन बिंदु है जिसे आप कॉल कर सकते हैं और टोकन और उसके गुणों को मान्य करने के लिए उपयोग किए जाने वाले अतिरिक्त मेटाडेटा प्राप्त कर सकते हैं।PyJWKClientPyJWT
  2. दूसरा, आपके पास विधि है: verify()
    1. kidटोकन हस्ताक्षर को सत्यापित करने के लिए JWKS से उपयोग की गई कुंजी को हथियाने के लिए यह विधि कुंजी आईडी ( टोकन हेडर में मौजूद दावा) का उपयोग करती है। यदि यह चरण किसी भी संभावित त्रुटि से विफल हो जाता है, तो त्रुटि संदेश वापस आ जाता है;
    2. फिर, विधि अब तक एकत्रित जानकारी का उपयोग करके जेडब्ल्यूटी को डीकोड करने का प्रयास करती है। त्रुटियों के मामले में, यह त्रुटि संदेश देता है। सफल होने पर, टोकन पेलोड वापस कर दिया जाता है।

आइए देखें कि आगे के अनुभाग में हमारे निजी समापन बिंदु में कोड के इस टुकड़े का उपयोग कैसे करें।

Auth0 एक्सेस टोकन की पुष्टि करें

अंतिम पहेली टुकड़ा उस वर्ग को आयात करना है जिसे आपने अभी फ़ाइल में बनाया है और इसे एंडपॉइंट में उपयोग करें । यहां आपको बदलने की आवश्यकता है:utils.pyGET /api/private

  1. के लिए आयात खंड जोड़ने के लिए आयात अनुभाग को अपडेट करें VerifyToken, फिर अपने समापन बिंदु पर जाएं; आपको Responseकक्षा और statusवस्तु को आयात करने की भी आवश्यकता होगी fastapiताकि आप किसी त्रुटि के मामले में विस्तृत प्रतिक्रिया दे सकें;
  2. फिर, आपको VerifyTokenकक्षा को टोकन पास करके और विधि का परिणाम एक त्रुटि है या नहीं, इसकी जाँच करके समापन बिंदु को समायोजित करने की आवश्यकता होगी ।verify()

यहां बताया गया है कि उपरोक्त सभी परिवर्तनों के साथ आपकी फ़ाइल कैसी दिखनी चाहिए:main.py

"""main.py
Python FastAPI Auth0 integration example
"""
 
from fastapi import Depends, FastAPI, Response, status  # 👈 new imports
from fastapi.security import HTTPBearer
 
from .utils import VerifyToken  # 👈 new import

# Scheme for the Authorization header
token_auth_scheme = HTTPBearer()
 
# Creates app instance
app = FastAPI()
 
 
@app.get("/api/public")
def public():
   """No access token required to access this route"""
 
   result = {
       "status": "success",
       "msg": ("Hello from a public endpoint! You don't need to be "
               "authenticated to see this.")
   }
   return result
 
 
@app.get("/api/private")
def private(response: Response, token: str = Depends(token_auth_scheme)):  # 👈 updated code
    """A valid access token is required to access this route"""
 
    result = VerifyToken(token.credentials).verify()  # 👈 updated code

    # 👇 new code
    if result.get("status"):
       response.status_code = status.HTTP_400_BAD_REQUEST
       return result
    # 👆 new code
 
    return result

इस अपडेट के साथ, आप अपने सुरक्षित एंडपॉइंट को ठीक से सेट कर रहे हैं और आपको आवश्यक एक्सेस टोकन के लिए सभी सत्यापन चरण कर रहे हैं। मैं

भले ही आपने अपने सर्वर को --reloadध्वज के साथ शुरू किया क्योंकि आपको यह सुनिश्चित करने की आवश्यकता है कि कॉन्फ़िगरेशन लोड हो गया है, यह uvicornप्रक्रिया को समाप्त करने और फिर सर्वर को पुनरारंभ करने का एक अच्छा समय है । यह .configफ़ाइल या पर्यावरण चर से कॉन्फ़िगरेशन पैरामीटर के साथ आपके एपीआई की उचित कार्यक्षमता की गारंटी देगा ।

इससे पहले कि आप FastAPIसर्वर में संरक्षित एंडपॉइंट के लिए अनुरोध कर सकें , आपको Auth0 से एक्सेस टोकन की आवश्यकता है। आप इसे Testअपने API के टैब में Auth0 डैशबोर्ड से कॉपी करके प्राप्त कर सकते हैं ।

आप एक्सेस टोकन प्राप्त करने POSTके लिए Auth0 के एंडपॉइंट पर कर्ल अनुरोध का उपयोग कर सकते हैं, और आप इस अनुरोध को Auth0 डैशबोर्ड में अपने API के टैब से कॉपी कर सकते हैं । कर्ल अनुरोध इस तरह दिखेगा; आवश्यकतानुसार मानों को भरना याद रखें:oauth/tokenTest

curl -X 'POST' \
--url 'https://<YOUR DOMAIN HERE>/oauth/token' \
 --header 'content-type: application/x-www-form-urlencoded' \
 --data grant_type=client_credentials \
 --data 'client_id=<YOUR CLIENT ID HERE>' \
 --data client_secret=<YOUR CLIENT SECRET HERE> \
 --data audience=<YOUR AUDIENCE HERE>

कमांड लाइन में, आपको अपने वाहक टोकन वाली एक प्रतिक्रिया दिखाई देनी चाहिए, जैसे कि:​

{
    "access_token": "<YOUR_BEARER_TOKEN>",
    "expires_in": 86400,
    "token_type": "Bearer"
}

अब आप निजी समापन बिंदु तक पहुँचने के लिए इस एक्सेस टोकन का उपयोग कर सकते हैं:

curl -X 'GET' \
--url 'http://127.0.0.1:8000/api/private' \
--header  'Authorization: Bearer <YOUR_BEARER_TOKEN>'

यदि अनुरोध सफल होता है, तो सर्वर एक्सेस टोकन के पेलोड को वापस भेज देगा:

{
    "iss": "https://<YOUR_DOMAIN>/",
    "sub": "iojadoijawdioWDasdijasoid@clients",
    "aud": "http://<YOUR_AUDIENCE>",
    "iat": 1630341660,
    "exp": 1630428060,
    "azp": "ADKASDawdopjaodjwopdAWDdsd",
    "gty": "client-credentials"
}

ध्यान रखें कि यदि सत्यापन विफल हो जाता है, तो आपको इसका विवरण देखना चाहिए कि क्या गलत हुआ।

और बस इतना ही - आपने निजी समापन बिंदु की सुरक्षा करना और उसकी सुरक्षा का परीक्षण करना समाप्त कर दिया है।

संक्षिप्त

आपने इस ब्लॉग पोस्ट में काफी कुछ सीखा। शुरू करने के लिए, आपने FastAPIदो समापन बिंदुओं को लागू करके मूल बातें सीखीं - एक सार्वजनिक, एक निजी। आपने देखा कि इन दोनों अंतिम बिंदुओं के लिए अनुरोध करना कितना आसान है। आपने एक सत्यापन वर्ग बनाया और देखा कि कैसे PyJWT आपको Auth0 एक्सेस टोकन को मान्य करने में मदद करता है, और आपने सीखा कि JWKS क्या है।

आप Auth0 डैशबोर्ड में अपना API बनाने की प्रक्रिया से गुजरे हैं। आपने यह भी सीखा कि निर्भरता इंजेक्शन प्रणाली का लाभ उठाकर अपने एक अंतिम बिंदु को कैसे सुरक्षित किया जाए FastAPI आपको एकीकरण को लागू करने में मदद करने के लिए प्रदान करता है। और आपने यह सब बहुत जल्दी किया।

संक्षेप में, आपने सीखा है कि के साथ उठना और दौड़ना कितना आसान है FastAPI, साथ ही साथ अपने समापन बिंदुओं की सुरक्षा के लिए Auth0 का उपयोग कैसे करना है।

इस GitHub रेपो में , आपको आज बनाए गए सैंपल एप्लिकेशन का पूरा कोड मिलेगा। यदि आपके कोई प्रश्न हैं, तो उन्हें इस ब्लॉग पोस्ट के लिए सामुदायिक फ़ोरम थ्रेड में पूछें।

#python #auth0 #fastapi

Zak Dyer

Zak Dyer

1633743973

Protecting an API in FastAPI with Auth0

Protecting your API can be a hard task but if you use Auth0 you can do it in a few easy steps!

In this video you will learn how to leverage the FastAPI dependency injection system to integrate your API with Auth0 and protect your endpoints.

You'll see how that affects your API documentation and how you can use code we provided to verify your Auth0 access token

Chapters:
00:00 Intro
1:22 Running the Example Project
3:33 Dependency Injection System in FastAPI
5:09 Configuring an API in Auth0
7:10 Protecting the Endpoint
16:16 Making Protected Requests
24:54 Outro

Links: 
- Code sample:  https://github.com/jtemporal/fastapi-and-auth0 
- Securing a FastAPI server with Auth0 by Mark Halpin: http://auth0.com/blog/build-and-secure-fastapi-server-with-auth0 
- A very complete blog post on "How to Handle JWTs in Python": https://auth0.com/blog/how-to-handle-jwt-in-python/ 
- Auth0's page on JWTs: https://auth0.com/learn/json-web-tokens/ 
- Auth0's free ebook on JWTs: https://auth0.com/resources/ebooks/jwt-handbook 
- Documentation on Python virtual environments: https://docs.python.org/3/library/venv.html#creating-virtual-environments 

#api #auth0 #fastapi #python 

How to Protect an API in FastAPI with Auth0

Learn how to protect an API in FastAPI with Auth0. Learn how to leverage the FastAPI dependency injection system to integrate your API with Auth0 and protect your endpoints. You'll see how that affects your API documentation and how you can use code we provided to verify your Auth0 access token

Chapters: 
00:00 Intro 
1:22 Running the Example Project 
3:33 Dependency Injection System in FastAPI 
5:09 Configuring an API in Auth0 
7:10 Protecting the Endpoint 
16:16 Making Protected Requests 
24:54 Outro

Links: 
- Code sample: https://github.com/jtemporal/fastapi-and-auth0   
 

#api #fastapi #auth0

Cree y proteja un servidor FastAPI con Auth0

Aprenda los conceptos básicos de FastAPI, cómo configurar rápidamente un servidor y proteger los puntos finales con Auth0.

FastAPI es un marco Python relativamente nuevo que le permite crear aplicaciones muy rápidamente. Este marco le permite leer datos de solicitud de API sin problemas con módulos integrados y es una alternativa ligera a Flask.

En este artículo, FastAPIrepasaremos las características de , configuraremos una API básica, protegeremos un endpoint usando Auth0 y aprenderá lo simple que es comenzar.

Prerrequisitos

Antes de comenzar a compilar con FastAPI , debe tener Python y una cuenta Auth0 gratuita; puedes registrarte aquí .3.8.2

Si tiene instalada esa versión de Python y su cuenta Auth0, puede crear una nueva FastAPIaplicación. Para comenzar, cree un nuevo directorio para desarrollar. Para este ejemplo, creará un directorio llamado y una subcarpeta llamada ; esta subcarpeta es donde vivirá su código.fastapi-exampleapplication

En la carpeta, cree un entorno virtual con el siguiente comando:fastapi-example

python3 -m venv .env

Esto crea un entorno virtual y separa las dependencias del resto de las bibliotecas de su computadora. En otras palabras, no contamina el espacio de nombres global con bibliotecas y dependencias, lo que podría afectar a otros proyectos de Python.

Después de crear el entorno virtual, debe activarlo. Para los sistemas operativos basados ​​en Unix, aquí está el comando:

source .env/bin/activate

Si está en otro sistema operativo, puede encontrar una lista de cómo puede activar un entorno en esta página de documentación . Después de la activación de su entorno virtual, puede instalar los paquetes que se van a usar: FastAPI, uvicorn servidor, pyjwt y actualización pip:

pip install -U pip
pip install fastapi uvicorn 'pyjwt[crypto]'

Empiece a utilizar FastAPI

Ahora que todas las bibliotecas están instaladas, puede crear un archivo dentro de la carpeta; ahí es donde vivirá su código API. El contenido del se verá así:main.pyapplicationmain.py

"""main.py
Python FastAPI Auth0 integration example
"""
 
from fastapi import FastAPI
# Creates app instance
app = FastAPI()
 
 
@app.get("/api/public")
def public():
    """No access token required to access this route"""

    result = {
        "status": "success",
        "msg": ("Hello from a public endpoint! You don't need to be "
                "authenticated to see this.")
    }
    return result

Analicemos esto: - Para empezar, está importando la FastAPIbiblioteca; - Luego, cree su aplicación creando una instancia de un objeto; - Después de eso, se usa para definir una ruta que maneja las solicitudes; - Finalmente, tiene la función de operación de ruta llamada , que es una función que se ejecutará cada vez que se llame a esa ruta, y devuelve un diccionario con el mensaje de bienvenida.FastAPI()@app.getGETpublic()

Ahora que tiene su primer código de punto final, para que el servidor esté en funcionamiento, ejecute el siguiente comando en el directorio raíz del proyecto:

uvicorn application.main:app --reload

Con su servidor en ejecución, puede ir a http://127.0.0.1:8000/docs para ver la documentación generada automáticamente para el primer punto final como se muestra en la siguiente imagen:

Página de documentación de FastAPI que muestra el punto final público

O puede realizar su primera solicitud en una nueva ventana de terminal usando cURL. Tenga en cuenta que si es un usuario de Windows en una versión anterior del sistema operativo, tendrá que instalar curl antes de ejecutar el siguiente comando:

curl -X 'GET' \
  --url http://127.0.0.1:8000/api/public

Y debería ver un JSON como resultado de la solicitud que acaba de hacer similar a esto:

{
  "status": "success",
  "msg": "Hello from a public endpoint! You don't need to be authenticated to see this."
}

En aras de la simplicidad, usará el cURLpara el resto de esta publicación.

Crear un punto final privado

Ahora que está configurado un servidor API base, agregará un punto final más a su archivo. En esta aplicación, tendrás una ruta disponible para todos y una ruta a la que solo tú puedes acceder con el token de acceso que obtendrás de Auth0.main.pyGET /api/publicGET /api/private

Ahora necesitas actualizar el archivo. Esto es lo que necesitará cambiar en la sección de importaciones:main.py

  • Primero, necesita importar Dependsdesde el fastapimódulo, ese es el sistema de inyección de dependencia FastAPI;
  • Luego, también necesitará importar la HTTPBearerclase del módulo, un esquema de seguridad integrado para encabezados de autorización con tokens de portador;fastapi.security
  • Deberá crear el esquema de autorización basado en HTTPBearer. Esto se utilizará para garantizar la presencia del encabezado de autorización con el Bearertoken en cada solicitud realizada al punto final privado.

El token informa a la API que el portador del token ha sido autorizado para acceder a la API y realizar acciones específicas especificadas por el alcance que se otorgó durante la autorización.

Además de actualizar las importaciones, debe implementar el punto final privado. El punto final también aceptará solicitudes, y así es como se ve el código por ahora:/api/privateGETmain.py

"""main.py
Python FastAPI Auth0 integration example
"""
 
from fastapi import Depends, FastAPI  # 👈 new imports
from fastapi.security import HTTPBearer  # 👈 new imports


# Scheme for the Authorization header
token_auth_scheme = HTTPBearer()  # 👈 new code
 
# Creates app instance
app = FastAPI()

@app.get("/api/public")
def public():
    """No access token required to access this route"""
 
    result = {
        "status": "success",
        "msg": ("Hello from a public endpoint! You don't need to be "
                "authenticated to see this.")
    }
    return result


# new code 👇
@app.get("/api/private")
def private(token: str = Depends(token_auth_scheme)):
    """A valid access token is required to access this route"""
 
    result = token.credentials

    return result

La Dependsclase es responsable de evaluar cada solicitud que recibe un punto final determinado frente a una función, clase o instancia. En este caso, evaluará las solicitudes contra el HTTPBeareresquema que verificará la solicitud de un encabezado de autorización con un token de portador.

Puede encontrar más detalles sobre cómo FastAPI funciona la inyección de dependencia en su documentación .

Ahora su punto final privado devuelve el token recibido. Si no se proporciona ningún token, devolverá un 403 Forbiddencódigo de estado con el detalle que dice que sí "Not authenticated". Debido a que usó la --reloadbandera mientras ejecutaba su servidor, no necesita volver a ejecutar el comando; uvicornrecogerá los cambios y actualizará el servidor cada vez que guarde sus archivos. Ahora haga una solicitud al punto final para verificar su comportamiento. Primero, hagamos una solicitud sin pasar un encabezado de autorización:GET /api/private

curl -X 'GET' \
  --url 'http://127.0.0.1:8000/api/private'
# {"detail": "Not authenticated"}

Y ahora, si realiza una solicitud con el encabezado de autorización, pero con una cadena aleatoria como valor de token, debería ver el mismo valor aleatorio como resultado:

curl -X 'GET' \
  --url 'http://127.0.0.1:8000/api/private' \
  --header 'Authorization: Bearer FastAPI is awesome'
# "FastAPI is awesome"

Como puede ver, su punto final no está protegido, ya que acepta cualquier cadena como valor para el encabezado de autorización. No es suficiente recibir un encabezado de autorización; también debe verificar el valor del token de portador para permitir que alguien acceda al punto final. Arreglemos ese comportamiento.

Configurar Auth0 una API

Antes de llegar al punto en el que esté listo para validar tokens en sus puntos finales, debe configurar una API en Auth0 . Cuando se configura esta API, obtiene acceso a algunos datos que Auth0 requiere: una audiencia, una ID de cliente y un secreto de cliente.

También necesita tener acceso a esa información desde el servidor; ahí es donde entra en juego un archivo de configuración. Deberá crear un archivo de configuración llamado .configen la raíz del proyecto. Así es como .configdebería verse el archivo a continuación. Recuerde actualizar los valores en consecuencia:

# .config
 
[AUTH0]
DOMAIN = your.domain.auth0.com
API_AUDIENCE = your.api.audience
ALGORITHMS = RS256
ISSUER = https://your.domain.auth0.com/

Esta configuración es la primera pieza del rompecabezas para verificar los valores de configuración de Auth0 en la etapa de validación del token. Otra buena regla a seguir es nunca enviar sus archivos de configuración con variables de entorno al código fuente. Para evitar que esto suceda, debe crear un .gitignorearchivo en la raíz del proyecto y agregar el .configarchivo como una entrada:

# .gitignore
.config

Agregar validación de JSON Web Token (JWT)

Su FastAPIservidor ahora tiene una ruta, pero aún no está protegida. Solo verifica si tiene un encabezado de autorización en la solicitud, lo que significa que le falta un paso en el proceso: debe validar el token de acceso. Para hacer eso, necesita crear un objeto que realice todos los pasos para validar un JWT porque los tokens de acceso de Auth0 son JWT.GET /api/private

Para separar las responsabilidades de la definición de enrutamiento, debe crear un nuevo archivo llamado dentro de la carpeta para contener todo el código de la utilidad, como validar el token de acceso y leer la información de configuración.utils.pyapplication

Comience importando la osbiblioteca de Python , así como las bibliotecas PyJWTy configparser. La biblioteca del sistema operativo le da acceso a las variables de entorno. La biblioteca JWT le brinda funciones para verificar y validar un JWT. La ConfigParserclase de la biblioteca homónima proporciona una forma para que Python lea los ajustes de configuración que se encuentran en el .configarchivo que creó anteriormente. Y lo primero que tienes después de las importaciones es una función llamada , que puedes ver a continuación:set_up()

"""utils.py
"""

import os
import jwt
from configparser import ConfigParser

 
def set_up():
    """Sets up configuration for the app"""

    env = os.getenv("ENV", ".config")

    if env == ".config":
        config = ConfigParser()
        config.read(".config")
        config = config["AUTH0"]
    else:
        config = {
            "DOMAIN": os.getenv("DOMAIN", "your.domain.com"),
            "API_AUDIENCE": os.getenv("API_AUDIENCE", "your.audience.com"),
            "ISSUER": os.getenv("ISSUER", "https://your.domain.com/"),
            "ALGORITHMS": os.getenv("ALGORITHMS", "RS256"),
        }
    return config

La función se encarga de leer el archivo y crear un objeto de configuración que funciona como un diccionario. Debido a que este código de muestra está preparado para ejecutarse también en variables de entorno, la función por defecto intentará leer el archivo. Puede cambiar este comportamiento estableciendo la variable de entorno en cualquier otro valor, en cuyo caso se creará un diccionario leyendo todas las variables de entorno que puede ver en la cláusula anterior.set_up().configset_up().configENVelse

La siguiente pieza del rompecabezas es donde ocurre la magia. Creará una VerifyTokenclase para manejar la validación del token JWT:

# paste the code 👇 after the set_up() function in the utils.py file
class VerifyToken():
    """Does all the token verification using PyJWT"""

    def __init__(self, token):
        self.token = token
        self.config = set_up()

        # This gets the JWKS from a given URL and does processing so you can
        # use any of the keys available
        jwks_url = f'https://{self.config["DOMAIN"]}/.well-known/jwks.json'
        self.jwks_client = jwt.PyJWKClient(jwks_url)

    def verify(self):
        # This gets the 'kid' from the passed token
        try:
            self.signing_key = self.jwks_client.get_signing_key_from_jwt(
                self.token
            ).key
        except jwt.exceptions.PyJWKClientError as error:
            return {"status": "error", "msg": error.__str__()}
        except jwt.exceptions.DecodeError as error:
            return {"status": "error", "msg": error.__str__()}

        try:
            payload = jwt.decode(
                self.token,
                self.signing_key,
                algorithms=self.config["ALGORITHMS"],
                audience=self.config["API_AUDIENCE"],
                issuer=self.config["ISSUER"],
            )
        except Exception as e:
            return {"status": "error", "message": str(e)}

        return payload

Analicemos esta clase para comprender los pasos aquí:

  1. Primero, tienes el método: __init__()
    1. Este método es responsable de especificar el tokenparámetro que VerifyTokennecesita la clase;
    2. También ejecuta la función para construir la configuración que necesitará la clase;set_up()
    3. Y finalmente, establece la ruta del JWKSarchivo usando el PyJWKClientdel PyJWTpaquete. Un conjunto de claves web JSON, o JWKS para abreviar, contiene la información necesaria para validar una firma de token y asegurarse de que sea un token válido. Debido a que Auth0 implementa OAuth 2.0, tiene un punto final "conocido" al que puede llamar y obtener los metadatos adicionales utilizados para validar el token y sus propiedades.
  2. En segundo lugar, tienes el método: verify()
    1. Este método usa el ID de clave ( kidreclamo presente en el encabezado del token) para tomar la clave utilizada del JWKS para verificar la firma del token. Si este paso falla por alguno de los posibles errores, se devuelve el mensaje de error;
    2. Luego, el método intenta decodificar el JWT utilizando la información recopilada hasta ahora. En caso de errores, devuelve el mensaje de error. Cuando tiene éxito, se devuelve la carga útil del token.

Veamos cómo usar este fragmento de código en nuestro punto final privado en la sección siguiente.

Validar un token de acceso Auth0

La pieza final del rompecabezas es importar la clase que acaba de crear en el archivo y usarla en el punto final. Esto es lo que necesita cambiar:utils.pyGET /api/private

  1. Actualice la sección de importaciones para agregar la cláusula de importación para VerifyToken, luego diríjase a su punto final; también necesitará importar la Responseclase y el statusobjeto desde fastapipara que pueda dar una respuesta detallada en caso de error;
  2. Luego, deberá ajustar el punto final pasando el token a la VerifyTokenclase y verificando si el resultado del método es un error.verify()

Así es como debería verse su archivo con todos los cambios anteriores:main.py

"""main.py
Python FastAPI Auth0 integration example
"""
 
from fastapi import Depends, FastAPI, Response, status  # 👈 new imports
from fastapi.security import HTTPBearer
 
from .utils import VerifyToken  # 👈 new import

# Scheme for the Authorization header
token_auth_scheme = HTTPBearer()
 
# Creates app instance
app = FastAPI()
 
 
@app.get("/api/public")
def public():
   """No access token required to access this route"""
 
   result = {
       "status": "success",
       "msg": ("Hello from a public endpoint! You don't need to be "
               "authenticated to see this.")
   }
   return result
 
 
@app.get("/api/private")
def private(response: Response, token: str = Depends(token_auth_scheme)):  # 👈 updated code
    """A valid access token is required to access this route"""
 
    result = VerifyToken(token.credentials).verify()  # 👈 updated code

    # 👇 new code
    if result.get("status"):
       response.status_code = status.HTTP_400_BAD_REQUEST
       return result
    # 👆 new code
 
    return result

Con esta actualización, está configurando correctamente su punto final protegido y realizando todos los pasos de verificación para los tokens de acceso que necesita. 🎉

Aunque inició su servidor con la --reloadbandera porque necesita asegurarse de que la configuración esté cargada, es un buen momento para terminar el uvicornproceso y luego reiniciar el servidor. Eso garantizará la correcta funcionalidad de su API con los parámetros de configuración del .configarchivo o variables de entorno.

Antes de poder realizar solicitudes al punto final protegido en el FastAPIservidor, necesita el token de acceso de Auth0. Puede obtenerlo copiándolo desde el panel de Auth0 en la Testpestaña de su API.

También puede usar una POSTsolicitud curl al punto final de Auth0 para obtener el token de acceso, y puede copiar esta solicitud desde la pestaña de su API en el panel de Auth0. La solicitud de curl se verá así; recuerde completar los valores según sea necesario:oauth/tokenTest

curl -X 'POST' \
--url 'https://<YOUR DOMAIN HERE>/oauth/token' \
 --header 'content-type: application/x-www-form-urlencoded' \
 --data grant_type=client_credentials \
 --data 'client_id=<YOUR CLIENT ID HERE>' \
 --data client_secret=<YOUR CLIENT SECRET HERE> \
 --data audience=<YOUR AUDIENCE HERE>

En la línea de comando, debería ver una respuesta que contiene su token de portador, como esta:

{
    "access_token": "<YOUR_BEARER_TOKEN>",
    "expires_in": 86400,
    "token_type": "Bearer"
}

Ahora puede usar este token de acceso para acceder al punto final privado:

curl -X 'GET' \
--url 'http://127.0.0.1:8000/api/private' \
--header  'Authorization: Bearer <YOUR_BEARER_TOKEN>'

Si la solicitud tiene éxito, el servidor devolverá la carga útil del token de acceso:

{
    "iss": "https://<YOUR_DOMAIN>/",
    "sub": "iojadoijawdioWDasdijasoid@clients",
    "aud": "http://<YOUR_AUDIENCE>",
    "iat": 1630341660,
    "exp": 1630428060,
    "azp": "ADKASDawdopjaodjwopdAWDdsd",
    "gty": "client-credentials"
}

Tenga en cuenta que si la validación falla, debería ver los detalles de lo que salió mal.

Y eso es todo: ha terminado de proteger el punto final privado y de probar su protección.

Resumen

Aprendiste bastantes cosas en esta publicación de blog. Para empezar, aprendió los conceptos básicos de la FastAPIimplementación de dos puntos finales: uno público y otro privado. Viste lo simple que es realizar solicitudes a estos dos puntos finales. Creó una clase de verificación y vio cómo PyJWT lo ayuda a validar un token de acceso Auth0, y aprendió qué es JWKS.

Pasó por el proceso de creación de su API en el panel de Auth0. También aprendió cómo proteger uno de sus puntos finales aprovechando el sistema de inyección de dependencia que proporciona FastAPI para ayudarlo a implementar integraciones. E hiciste todo esto muy rápido.

En resumen, ha aprendido lo fácil que es ponerse en marcha y FastAPIcómo utilizar Auth0 para proteger sus puntos finales.

En este repositorio de GitHub , encontrará el código completo de la aplicación de muestra que creó hoy. Si tiene alguna pregunta, hágala en el hilo del foro de la comunidad para esta publicación de blog.

Enlace: https://auth0.com

#pythom #fastapi #auth0

 

Hong  Nhung

Hong Nhung

1633744445

Xây dựng và bảo mật máy chủ FastAPI với Auth0

Tìm hiểu kiến ​​thức cơ bản về FastAPI, cách nhanh chóng thiết lập máy chủ và bảo mật điểm cuối với Auth0.

FastAPI là một khung Python tương đối mới cho phép bạn tạo các ứng dụng rất nhanh chóng. Khuôn khổ này cho phép bạn đọc dữ liệu yêu cầu API một cách liền mạch với các mô-đun tích hợp sẵn và là một giải pháp thay thế nhẹ cho Flask.

Trong bài viết này, chúng ta sẽ xem xét các tính năng của FastAPI, thiết lập một API cơ bản, bảo vệ một điểm cuối bằng Auth0 và bạn sẽ biết cách bắt đầu đơn giản như thế nào.

Điều kiện tiên quyết

Trước khi bắt đầu xây dựng với FastAPI , bạn cần có Python và tài khoản Auth0 miễn phí; bạn có thể đăng ký tại đây .3.8.2

Nếu bạn đã cài đặt phiên bản Python đó và tài khoản Auth0 của mình, bạn có thể tạo một FastAPIứng dụng mới . Để bắt đầu, hãy tạo một thư mục mới để phát triển bên trong. Đối với ví dụ này, bạn sẽ tạo một thư mục được gọi và một thư mục con được gọi là ; thư mục con này là nơi mã của bạn sẽ tồn tại.fastapi-exampleapplication

Trong thư mục, tạo một môi trường ảo bằng lệnh sau:fastapi-example

python3 -m venv .env

Điều này tạo ra một môi trường ảo và nó phân tách các phần phụ thuộc khỏi phần còn lại của các thư viện máy tính của bạn. Nói cách khác, bạn không làm ô nhiễm không gian tên chung với các thư viện và phần phụ thuộc, điều này có thể ảnh hưởng đến các dự án Python khác.

Sau khi tạo môi trường ảo, bạn cần kích hoạt nó. Đối với hệ điều hành dựa trên Unix, đây là lệnh:

source .env/bin/activate

Nếu bạn đang sử dụng hệ điều hành khác, bạn có thể tìm thấy danh sách cách bạn có thể kích hoạt một môi trường trên trang tài liệu này . Sau khi kích hoạt môi trường ảo của mình, bạn có thể cài đặt các gói bạn sẽ sử dụng : FastAPI, uvicorn server, pyjwt và cập nhật pip:

pip install -U pip
pip install fastapi uvicorn 'pyjwt[crypto]'

Bắt đầu với FastAPI

Bây giờ tất cả các thư viện đã được cài đặt, bạn có thể tạo một tệp bên trong thư mục; đó là nơi mã API của bạn sẽ tồn tại. Nội dung của di chúc như sau:main.pyapplicationmain.py

"""main.py
Python FastAPI Auth0 integration example
"""
 
from fastapi import FastAPI
# Creates app instance
app = FastAPI()
 
 
@app.get("/api/public")
def public():
    """No access token required to access this route"""

    result = {
        "status": "success",
        "msg": ("Hello from a public endpoint! You don't need to be "
                "authenticated to see this.")
    }
    return result

Hãy chia nhỏ điều này: - Để bắt đầu, bạn đang nhập FastAPIthư viện; - Sau đó, tạo ứng dụng của bạn bằng cách khởi tạo một đối tượng; - Sau đó, bạn sử dụng để xác định một tuyến xử lý các yêu cầu; - Cuối cùng, bạn có chức năng hoạt động đường dẫn được gọi , đây là một chức năng sẽ chạy mỗi khi tuyến đường đó được gọi và nó trả về một từ điển với thông báo chào mừng.FastAPI()@app.getGETpublic()

Bây giờ bạn đã có mã điểm cuối đầu tiên của mình, để khởi động và chạy máy chủ, hãy chạy lệnh sau trên thư mục gốc của dự án:

uvicorn application.main:app --reload

Khi máy chủ của bạn đang chạy, bạn có thể truy cập http://127.0.0.1:8000/docs để xem tài liệu được tạo tự động cho điểm cuối đầu tiên như được hiển thị trong hình ảnh bên dưới:

Trang tài liệu FastAPI hiển thị điểm cuối công khai

Hoặc bạn có thể thực hiện yêu cầu đầu tiên của mình trong một cửa sổ đầu cuối mới bằng cách sử dụng cURL. Hãy nhớ rằng nếu bạn là người dùng Windows trên phiên bản hệ điều hành cũ hơn, bạn sẽ phải cài đặt curl trước khi chạy lệnh sau:

curl -X 'GET' \
  --url http://127.0.0.1:8000/api/public

Và bạn sẽ thấy một JSON là kết quả của yêu cầu bạn vừa thực hiện tương tự như sau:

{
  "status": "success",
  "msg": "Hello from a public endpoint! You don't need to be authenticated to see this."
}

Vì mục đích đơn giản, bạn sẽ sử dụng cURLphần còn lại của bài đăng này.

Tạo một điểm cuối riêng tư

Bây giờ một máy chủ API cơ sở đã được thiết lập, bạn sẽ thêm một điểm cuối nữa vào tệp của mình . Trong ứng dụng này, bạn sẽ có sẵn một tuyến đường cho mọi người và một tuyến đường mà chỉ bạn mới có thể truy cập bằng mã thông báo truy cập mà bạn sẽ nhận được từ Auth0.main.pyGET /api/publicGET /api/private

Bây giờ bạn cần cập nhật tệp. Đây là những gì bạn cần thay đổi đối với phần nhập:main.py

  • Đầu tiên, bạn cần nhập Dependstừ fastapimô-đun, đó là hệ thống tiêm phụ thuộc FastAPI;
  • Sau đó, bạn cũng sẽ cần nhập HTTPBearerlớp từ mô-đun, một sơ đồ bảo mật được tích hợp sẵn cho các tiêu đề ủy quyền có mã thông báo mang;fastapi.security
  • Bạn sẽ cần tạo kế hoạch ủy quyền dựa trên HTTPBearer. Điều này sẽ được sử dụng để đảm bảo sự hiện diện của tiêu đề ủy quyền với Bearermã thông báo trong mỗi yêu cầu được thực hiện tới điểm cuối riêng tư.

thông báo cho API biết rằng người mang mã thông báo đã được ủy quyền để truy cập API và thực hiện các hành động cụ thể được chỉ định theo phạm vi đã được cấp trong quá trình ủy quyền.

Ngoài việc cập nhật các lần nhập, bạn cần triển khai điểm cuối riêng. Điểm cuối cũng sẽ chấp nhận các yêu cầu và đây là mã trông như thế nào bây giờ:/api/privateGETmain.py

"""main.py
Python FastAPI Auth0 integration example
"""
 
from fastapi import Depends, FastAPI  # 👈 new imports
from fastapi.security import HTTPBearer  # 👈 new imports


# Scheme for the Authorization header
token_auth_scheme = HTTPBearer()  # 👈 new code
 
# Creates app instance
app = FastAPI()

@app.get("/api/public")
def public():
    """No access token required to access this route"""
 
    result = {
        "status": "success",
        "msg": ("Hello from a public endpoint! You don't need to be "
                "authenticated to see this.")
    }
    return result


# new code 👇
@app.get("/api/private")
def private(token: str = Depends(token_auth_scheme)):
    """A valid access token is required to access this route"""
 
    result = token.credentials

    return result

Các Dependslớp có trách nhiệm đánh giá từng yêu cầu rằng một thiết bị đầu cuối được nhận chống lại một chức năng, lớp, hoặc ví dụ. Trong trường hợp này, nó sẽ đánh giá các yêu cầu so với HTTPBearerlược đồ sẽ kiểm tra yêu cầu đối với tiêu đề ủy quyền với mã thông báo mang.

Bạn có thể tìm thêm chi tiết về cách FastAPI hoạt động của việc tiêm phụ thuộc trên tài liệu của nó .

Bây giờ điểm cuối riêng tư của bạn trả về mã thông báo đã nhận. Nếu không có mã thông báo nào được cung cấp, nó sẽ trả về 403 Forbiddenmã trạng thái với thông tin chi tiết cho biết bạn là ai "Not authenticated". Bởi vì bạn đã sử dụng --reloadcờ trong khi chạy máy chủ của mình, bạn không cần phải chạy lại lệnh; uvicornsẽ tiếp nhận các thay đổi và cập nhật máy chủ mỗi khi bạn lưu tệp của mình. Bây giờ hãy thực hiện một yêu cầu tới điểm cuối để kiểm tra hành vi của nó. Trước tiên, hãy thực hiện yêu cầu mà không cần chuyển tiêu đề ủy quyền:GET /api/private

curl -X 'GET' \
  --url 'http://127.0.0.1:8000/api/private'
# {"detail": "Not authenticated"}

Và bây giờ, nếu bạn thực hiện một yêu cầu với tiêu đề ủy quyền, nhưng với một chuỗi ngẫu nhiên làm giá trị mã thông báo, bạn sẽ thấy cùng một giá trị ngẫu nhiên như một kết quả:

curl -X 'GET' \
  --url 'http://127.0.0.1:8000/api/private' \
  --header 'Authorization: Bearer FastAPI is awesome'
# "FastAPI is awesome"

Như bạn có thể thấy, điểm cuối của bạn không được bảo vệ vì nó chấp nhận bất kỳ chuỗi nào làm giá trị cho tiêu đề ủy quyền. Nó là không đủ để nhận được một tiêu đề ủy quyền; bạn cũng phải xác minh giá trị của mã thông báo mang tên để cho phép ai đó truy cập vào điểm cuối. Hãy sửa hành vi đó.

Thiết lập Auth0 một API

Trước khi đến thời điểm bạn đã sẵn sàng xác thực mã thông báo trong các điểm cuối của mình, bạn cần thiết lập một API trong Auth0 . Khi API này được thiết lập, bạn có quyền truy cập vào một vài thông tin mà Auth0 yêu cầu - đối tượng, ID khách hàng và bí mật của ứng dụng khách.

Bạn cũng cần có quyền truy cập vào thông tin đó từ bên trong máy chủ; đó là nơi một tệp cấu hình phát huy tác dụng. Bạn sẽ cần tạo một tệp cấu hình được gọi .configở gốc của dự án. Đây là những gì .configtệp sẽ giống như bên dưới. Hãy nhớ cập nhật các giá trị cho phù hợp:

# .config
 
[AUTH0]
DOMAIN = your.domain.auth0.com
API_AUDIENCE = your.api.audience
ALGORITHMS = RS256
ISSUER = https://your.domain.auth0.com/

Cấu hình này là phần đầu tiên của câu đố kiểm tra cài đặt cấu hình Auth0 trong giai đoạn xác thực mã thông báo. Một quy tắc tốt khác cần tuân theo là không bao giờ gán các tệp cấu hình của bạn với các biến môi trường thành mã nguồn. Để ngăn điều này xảy ra, bạn nên tạo một .gitignoretệp trong thư mục gốc của dự án và thêm .configtệp dưới dạng mục nhập:

# .gitignore
.config

Thêm xác thực mã thông báo web JSON (JWT)

FastAPIMáy chủ của bạn hiện có một tuyến, nhưng nó chưa được bảo vệ. Nó chỉ kiểm tra xem bạn có tiêu đề ủy quyền trong yêu cầu hay không, có nghĩa là bạn đang thiếu một bước trong quy trình: bạn cần xác thực mã thông báo truy cập. Để làm điều đó, bạn cần tạo một đối tượng thực hiện tất cả các bước để xác thực JWT vì mã thông báo truy cập của Auth0 là JWT.GET /api/private

Để tách các trách nhiệm khỏi định nghĩa định tuyến, bạn nên tạo một tệp mới được gọi là bên trong thư mục để chứa tất cả mã tiện ích, như xác thực mã thông báo truy cập và đọc thông tin cấu hình.utils.pyapplication

Bắt đầu bằng cách nhập osthư viện Python , cũng như các thư viện PyJWTconfigparser. Thư viện hệ điều hành cung cấp cho bạn quyền truy cập vào các biến môi trường. Thư viện JWT cung cấp cho bạn các hàm để kiểm tra và xác thực JWT. Các ConfigParserlớp từ thư viện trùng tên cung cấp một cách cho Python đọc cài đặt cấu hình tìm thấy trong các .configtập tin mà bạn đã tạo trước đó. Và điều đầu tiên bạn có sau khi nhập là một hàm được gọi , bạn có thể thấy bên dưới:set_up()

"""utils.py
"""

import os
import jwt
from configparser import ConfigParser

 
def set_up():
    """Sets up configuration for the app"""

    env = os.getenv("ENV", ".config")

    if env == ".config":
        config = ConfigParser()
        config.read(".config")
        config = config["AUTH0"]
    else:
        config = {
            "DOMAIN": os.getenv("DOMAIN", "your.domain.com"),
            "API_AUDIENCE": os.getenv("API_AUDIENCE", "your.audience.com"),
            "ISSUER": os.getenv("ISSUER", "https://your.domain.com/"),
            "ALGORITHMS": os.getenv("ALGORITHMS", "RS256"),
        }
    return config

Các chức năng có trách nhiệm đọc tập tin và tạo ra một đối tượng cấu hình mà hoạt động giống như một cuốn từ điển. Bởi vì mã mẫu này cũng được chuẩn bị để chạy trên các biến môi trường, theo mặc định , hàm sẽ cố gắng đọc tệp. Bạn có thể thay đổi hành vi này bằng cách đặt biến môi trường thành bất kỳ giá trị nào khác, trong trường hợp đó, một từ điển sẽ được tạo bằng cách đọc tất cả các biến môi trường mà bạn có thể thấy trong mệnh đề trên.set_up().configset_up().configENVelse

Phần tiếp theo của câu đố là nơi điều kỳ diệu xảy ra. Bạn sẽ tạo một VerifyTokenlớp để xử lý xác thực mã thông báo JWT:

# paste the code 👇 after the set_up() function in the utils.py file
class VerifyToken():
    """Does all the token verification using PyJWT"""

    def __init__(self, token):
        self.token = token
        self.config = set_up()

        # This gets the JWKS from a given URL and does processing so you can
        # use any of the keys available
        jwks_url = f'https://{self.config["DOMAIN"]}/.well-known/jwks.json'
        self.jwks_client = jwt.PyJWKClient(jwks_url)

    def verify(self):
        # This gets the 'kid' from the passed token
        try:
            self.signing_key = self.jwks_client.get_signing_key_from_jwt(
                self.token
            ).key
        except jwt.exceptions.PyJWKClientError as error:
            return {"status": "error", "msg": error.__str__()}
        except jwt.exceptions.DecodeError as error:
            return {"status": "error", "msg": error.__str__()}

        try:
            payload = jwt.decode(
                self.token,
                self.signing_key,
                algorithms=self.config["ALGORITHMS"],
                audience=self.config["API_AUDIENCE"],
                issuer=self.config["ISSUER"],
            )
        except Exception as e:
            return {"status": "error", "message": str(e)}

        return payload

Hãy chia nhỏ lớp này để hiểu các bước ở đây:

  1. Đầu tiên, bạn có phương pháp: __init__()
    1. Phương thức này có nhiệm vụ xác định tokentham số mà VerifyTokenlớp cần;
    2. Nó cũng chạy chức năng để xây dựng cấu hình mà lớp sẽ cần;set_up()
    3. Và cuối cùng, nó đặt đường dẫn cho JWKStập tin bằng cách sử dụng PyJWKClienttừ PyJWTgói. Bộ khóa web JSON, viết tắt là JWKS chứa thông tin cần thiết để xác thực chữ ký mã thông báo và đảm bảo rằng đó là mã thông báo hợp lệ. Vì Auth0 triển khai OAuth 2.0 nên nó có một điểm cuối "nổi tiếng" mà bạn có thể gọi và lấy siêu dữ liệu bổ sung được sử dụng để xác thực mã thông báo và các thuộc tính của nó.
  2. Thứ hai, bạn có phương pháp: verify()
    1. Phương pháp này sử dụng ID khóa ( kidxác nhận quyền sở hữu có trong tiêu đề mã thông báo) để lấy khóa được sử dụng từ JWKS để xác minh chữ ký mã thông báo. Nếu bước này không thành công bởi bất kỳ lỗi nào có thể xảy ra, thông báo lỗi sẽ được trả về;
    2. Sau đó, phương pháp cố gắng giải mã JWT bằng cách sử dụng thông tin thu thập được cho đến nay. Trong trường hợp có lỗi, nó sẽ trả về thông báo lỗi. Khi thành công, trọng tải mã thông báo được trả lại.

Hãy xem cách sử dụng đoạn mã này trong điểm cuối riêng tư của chúng tôi trong phần phía trước.

Xác thực mã thông báo truy cập Auth0

Mảnh ghép cuối cùng là nhập lớp bạn vừa tạo vào tệp và sử dụng nó trong điểm cuối. Đây là những gì bạn cần thay đổi:utils.pyGET /api/private

  1. Cập nhật phần nhập để thêm điều khoản nhập cho VerifyToken, sau đó đi đến điểm cuối của bạn; bạn cũng sẽ cần nhập Responselớp và statusđối tượng từ fastapiđó để bạn có thể đưa ra phản hồi chi tiết trong trường hợp có lỗi;
  2. Sau đó, bạn sẽ cần điều chỉnh điểm cuối bằng cách chuyển mã thông báo cho VerifyTokenlớp và kiểm tra xem kết quả của phương thức có phải là lỗi hay không.verify()

Đây là tệp của bạn sẽ trông như thế nào với tất cả các thay đổi ở trên:main.py

"""main.py
Python FastAPI Auth0 integration example
"""
 
from fastapi import Depends, FastAPI, Response, status  # 👈 new imports
from fastapi.security import HTTPBearer
 
from .utils import VerifyToken  # 👈 new import

# Scheme for the Authorization header
token_auth_scheme = HTTPBearer()
 
# Creates app instance
app = FastAPI()
 
 
@app.get("/api/public")
def public():
   """No access token required to access this route"""
 
   result = {
       "status": "success",
       "msg": ("Hello from a public endpoint! You don't need to be "
               "authenticated to see this.")
   }
   return result
 
 
@app.get("/api/private")
def private(response: Response, token: str = Depends(token_auth_scheme)):  # 👈 updated code
    """A valid access token is required to access this route"""
 
    result = VerifyToken(token.credentials).verify()  # 👈 updated code

    # 👇 new code
    if result.get("status"):
       response.status_code = status.HTTP_400_BAD_REQUEST
       return result
    # 👆 new code
 
    return result

Với bản cập nhật này, bạn đang thiết lập đúng điểm cuối được bảo vệ của mình và thực hiện tất cả các bước xác minh cho mã thông báo truy cập mà bạn cần. 🎉

Mặc dù bạn đã khởi động máy chủ của mình bằng --reloadcờ vì bạn cần đảm bảo cấu hình được tải, nhưng đây là thời điểm tốt để kết thúc uvicornquá trình và sau đó khởi động lại máy chủ. Điều đó sẽ đảm bảo chức năng thích hợp của API của bạn với các tham số cấu hình từ .configtệp hoặc biến môi trường.

Trước khi bạn có thể thực hiện các yêu cầu đến điểm cuối được bảo vệ trong FastAPImáy chủ, bạn cần mã thông báo truy cập từ Auth0. Bạn có thể lấy nó bằng cách sao chép nó từ bảng điều khiển Auth0 trong Testtab API của bạn.

Bạn cũng có thể sử dụng POSTyêu cầu curl tới điểm cuối của Auth0 để lấy mã thông báo truy cập và bạn có thể sao chép yêu cầu này từ tab API của mình trong bảng điều khiển Auth0. Yêu cầu cuộn tròn sẽ như thế này; nhớ điền các giá trị nếu cần:oauth/tokenTest

curl -X 'POST' \
--url 'https://<YOUR DOMAIN HERE>/oauth/token' \
 --header 'content-type: application/x-www-form-urlencoded' \
 --data grant_type=client_credentials \
 --data 'client_id=<YOUR CLIENT ID HERE>' \
 --data client_secret=<YOUR CLIENT SECRET HERE> \
 --data audience=<YOUR AUDIENCE HERE>

Trong dòng lệnh, bạn sẽ thấy một phản hồi có chứa mã thông báo mang của bạn, như sau:

{
    "access_token": "<YOUR_BEARER_TOKEN>",
    "expires_in": 86400,
    "token_type": "Bearer"
}

Bây giờ bạn có thể sử dụng mã thông báo truy cập này để truy cập điểm cuối riêng tư:

curl -X 'GET' \
--url 'http://127.0.0.1:8000/api/private' \
--header  'Authorization: Bearer <YOUR_BEARER_TOKEN>'

Nếu yêu cầu thành công, máy chủ sẽ gửi lại trọng tải của mã thông báo truy cập:

{
    "iss": "https://<YOUR_DOMAIN>/",
    "sub": "iojadoijawdioWDasdijasoid@clients",
    "aud": "http://<YOUR_AUDIENCE>",
    "iat": 1630341660,
    "exp": 1630428060,
    "azp": "ADKASDawdopjaodjwopdAWDdsd",
    "gty": "client-credentials"
}

Hãy nhớ rằng nếu xác thực không thành công, bạn sẽ xem chi tiết về những gì đã xảy ra.

Vậy là xong - bạn đã hoàn thành việc bảo vệ điểm cuối riêng tư và kiểm tra khả năng bảo vệ của nó.

Tóm tắt

Bạn đã học được khá nhiều điều trong bài đăng trên blog này. Để bắt đầu, bạn đã học những kiến ​​thức cơ bản về FastAPIviệc triển khai hai điểm cuối - một công khai, một riêng tư. Bạn đã thấy việc thực hiện yêu cầu đến cả hai điểm cuối này đơn giản như thế nào. Bạn đã tạo một lớp xác minh và xem cách PyJWT giúp bạn xác thực mã thông báo truy cập Auth0 và bạn đã biết JWKS là gì.

Bạn đã trải qua quá trình tạo API của mình trong bảng điều khiển Auth0. Bạn cũng đã học cách bảo mật một trong những điểm cuối của mình bằng cách tận dụng hệ thống tiêm phụ thuộc mà FastAPI cung cấp để giúp bạn triển khai tích hợp. Và bạn đã làm tất cả những điều này rất nhanh chóng.

Tóm lại, bạn đã học được cách dễ dàng thiết lập và chạy FastAPI, cũng như cách sử dụng Auth0 để bảo vệ các điểm cuối của bạn.

Trong repo GitHub này , bạn sẽ tìm thấy mã đầy đủ cho ứng dụng mẫu mà bạn đã tạo hôm nay. Nếu bạn có bất kỳ câu hỏi nào, hãy hỏi họ trong chuỗi diễn đàn cộng đồng cho bài đăng trên blog này.

Nguồn: https://auth0.com

#fastapi #python #auth0