[PYTHON] [Fast API + Firebase] Aufbau eines API-Servers für die Bearer-Authentifizierung

FastAPI ist praktisch. Ich persönlich verwende es als Framework, das es einfach macht, einen API-Server zu erstellen. Dieses Mal werden wir der Fast API eine Authentifizierungsfunktion hinzufügen.

** Achtung **: Setup wie FastAPI- und Firebase-Installation wird hier nicht als Voraussetzung erwähnt.

Inhaberzertifizierung

Ich denke, es besteht eine große Nachfrage, den Benutzer, der den Server angefordert hat, zu identifizieren und zu authentifizieren und die entsprechende Berechtigung für die angeforderte Ressource zu kontrollieren. Hier implementieren wir die Bearer-Authentifizierung, die einfach durch Hinzufügen zum HTTP-Header implementiert werden kann.

[Qiita] "Informationen zur Trägerauthentifizierung"

Kann als Schema im HTTP-Autorisierungsheader angegeben werden, z. B. "Authorization: Bearer ". Das Token-Format wird im token68-Format angegeben.

Da es schwierig ist, die Ausstellung und Überprüfung von "Token" selbst zu implementieren, werden wir diesmal Firebase verwenden.

Gesamtzusammensetzung

Das gesamte Bild der Bearer-Authentifizierung mit Firebase ist dargestellt.

image.png

  1. Der Client fragt den API-Server ab Melden Sie sich bei Firebase als entsprechender Benutzer an und erhalten Sie das "Token"
  2. Der Client wirft es über HTTP mit "Token" an den API-Server
  3. Der Server fragt Firebase nach dem HTTP-Header-Token ab, um ihn zu validieren. Wenn die Überprüfung erfolgreich ist, ist die Benutzeridentifikation / -authentifizierung abgeschlossen.
  4. Der Server reagiert angemessen auf die Anfrage

Einrichten des Firebase Admin SDK

Implementieren Sie die Authentifizierungsfunktion mithilfe des Firebase Admin SDK

Vorbereitung des privaten Schlüssels

Holen Sie sich im Voraus ein Firebase-Konto. Öffnen Sie zunächst die Projektkonsole (https://console.firebase.google.com/u/0/).

Öffnen Sie die Einstellungen über das Zahnradsymbol oben rechts image.png

Rufen Sie den privaten Schlüssel als JSON-Datei über die Schaltfläche unten auf der Registerkarte Dienstkonten ab. Speichern Sie es hier als account_key.json. image.png

SDK-Vorbereitung

$ pip install firebase_admin

Implementierung

API-Endpunkt

Bereiten Sie zunächst einen einfachen Endpunkt vor und erstellen Sie einen minimalen API-Server.

main.py


from fastapi import FastAPI

app = FastAPI()

@app.get("/api/")
async def hello():
    return {"msg":"Hello, this is API server"}

Lassen Sie uns einen Testserver mit uvicorn einrichten

$ uvicorn main:app --port 8001 --reload

Lassen Sie uns den API-Server als Testversion testen (der Webbrowser ist ebenfalls in Ordnung).

PS > curl http://localhost:8001/api
StatusCode        : 200
StatusDescription : OK
Content           : {"msg":"Hello, this is API server"}
RawContent        : HTTP/1.1 200 OK
                    Content-Length: 35
                    Content-Type: application/json
                    Date: Wed, 18 Nov 2020 11:11:20 GMT
                    Server: uvicorn

                    {"msg":"Hello, this is API server"}

Trägerzertifizierung hinzufügen

user.py


from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from fastapi import Depends, HTTPException, status, Response
from firebase_admin import auth, credentials
import firebase_admin

cred = credentials.Certificate('./account_key.json')
firebase_admin.initialize_app(cred)

def get_user(res: Response, cred: HTTPAuthorizationCredentials=Depends(HTTPBearer(auto_error=False))):
    if cred is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Bearer authentication required",
            headers={'WWW-Authenticate': 'Bearer realm="auth_required"'},
        )
    try:
        decoded_token = auth.verify_id_token(cred.credentials)
    except Exception as err:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=f"Invalid authentication credentials. {err}",
            headers={'WWW-Authenticate': 'Bearer error="invalid_token"'},
        )
    res.headers['WWW-Authenticate'] = 'Bearer realm="auth_required"'
    return decoded_token

Zuerst müssen Sie das Token aus dem Authorization-Header extrahieren. FastAPI ist praktisch, da Sie auch den Authentifizierungsheader der Anforderung überprüfen können.

[FastAPI] Query Parameters and String Validations
[Qiita] Firebase-Authentifizierungstokenerfassung mit Python und Tokenüberprüfung mit Fast API

Überprüfen Sie als Nächstes "Token". Der obige Code definiert, was zu tun ist, wenn "Token" nicht vorhanden und ungültig ist. Der Inhalt der Antwort auf den Fehler entspricht RFC 6750, der die Trägerauthentifizierung definiert. Wirf einfach "HTTPExeption" und die Fast API nimmt es auf und generiert eine Antwort, so dass es einfach ist.

Offizielle Firebase-Dokumentation Firebase Admin Python SDK
[[Qiita] Implementieren eines Trägerschemas, das RFC 6750 entspricht](https://qiita.com/uasi/items/cfb60588daa18c2ec6f5#rfc-6750-%E3%81%AB%E6%BA%96%E6 % 8B% A0% E3% 81% 97% E3% 81% 9F-Träger-% E3% 82% B9% E3% 82% AD% E3% 83% BC% E3% 83% A0% E3% 82% 92% E5% AE% 9F% E8% A3% 85% E3% 81% 99% E3% 82% 8B% E3% 81% AB% E3% 81% AF)

** Achtung **: Mit "HTTPBearer (auto_error = True)" (Standard) für Anforderungen ohne "Token"

PS > curl http://localhost:8001/api/me                            
curl : {"detail":"Not authenticated"}
PS > $error[0].exception
Der Remote-Server hat einen Fehler zurückgegeben: (403)Nicht verfügbar

Und Fast API generiert Ausnahmebehandlung + Antwort ohne Erlaubnis.

Authentifizierter API-Endpunkt

Fügen Sie einen API-Endpunkt hinzu, für den eine Benutzerauthentifizierung erforderlich ist.

main.py


from fastapi import FastAPI, Depends
from user import get_user

app = FastAPI()

@app.get("/api/")
async def hello():
    return {"msg":"Hello, this is API server"} 


@app.get("/api/me")
async def hello_user(user = Depends(get_user)):
    return {"msg":"Hello, user","uid":user['uid']} 

"uid" ist die Kennung des Benutzers, der sich bei Firebase angemeldet hat, und kann nicht nur E-Mail und Passwort identifizieren, sondern auch Benutzer, die sich bei verschiedenen Diensten wie Twitter und Google authentifiziert haben.

Prüfung

Lassen Sie uns tatsächlich die API vom Client aus treffen und die Antwort sehen.

Holen Sie sich "Token"

API-Schlüssel abrufen

Wählen Sie ein Projekt unter Firebase Console aus und kopieren Sie es unter Einstellungen> Allgemein. image.png

Klicken Sie auf die REST-API

Angenommen, der Benutzer (E-Mail & Passwort) ist bereits im Projekt registriert

{
  "email":"[email protected]",
  "password":"your password",
  "returnSecureToken":true
}

[Firebase] Auth REST API-Offizielle Dokumentation

PS >  curl -Method Post -Body $Body -Headers @{"content-type"="application/json"} $URL
StatusCode        : 200
StatusDescription : OK
Content           : {
                      "kind": "identitytoolkit#VerifyPasswordResponse",
                      "localId": "OZzdeAtK4VM4OlHHbUXTY6YNr8C3",
                      "email": "[email protected]",
                      "displayName": "",
                      "idToken": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjNlNTQ...
RawContent        : HTTP/1.1 200 OK
                    Pragma: no-cache
                    Vary: X-Origin,Referer,Origin,Accept-Encoding
                    X-XSS-Protection: 0
                    X-Frame-Options: SAMEORIGIN
                    X-Content-Type-Options: nosniff
                    Alt-Svc: h3-Q050=":443"; ma=2592000...

Die Antwort ist ebenfalls JSON und verwendet den Wert "idToken" für die Bearer-Authentifizierung.

Lauf

Erfolgsgeschichte

PS > curl -Headers @{"Authorization"="Bearer ${token}"} http://localhost:8001/api/me
StatusCode        : 200                                                         
StatusDescription : OK                                                          
Content           : {"msg":"Hello, user","uid":"OZzdeAtK4VM4OlHHbUXTY6YNr8C3"}  
RawContent        : HTTP/1.1 200 OK                                                                 
                    Content-Length: 58                                                              
                    Content-Type: application/json                                                  
                    Date: Fri, 20 Nov 2020 15:28:18 GMT                                             
                    Server: uvicorn                                                                 
                    WWW-Authenticate: Bearer realm="auth_required"       
                                                                                                           
                    {"msg":"Hello, user","uid":... 

Illegales Token-Beispiel

Versuchen Sie, mit dem Wert "Token" zu spielen und ihn zu übergeben

PS > curl -Headers @{"Authorization"="Bearer ${token}"} http://localhost:8001/api/me
curl : {"detail":"Invalid authentication credentials. Could not verify token signature."}

Beispiel für einen Token-Defekt

PS > curl http://localhost:8001/api/me                                              
curl : {"detail":"Bearer authentication required"}

Recommended Posts

[Fast API + Firebase] Aufbau eines API-Servers für die Bearer-Authentifizierung
[Studiennotiz] Erstellen Sie einen GeoJSON-Vektor-Kachelserver mit Fast API
Ausgabe von Firebase-Authentifizierungstoken in Python und Token-Validierung mit Fast API
Erstellen Sie eine Umgebung für das in Blender integrierte Python
Erstellen Sie einen NFS-Server unter Arch Linux
Erstellen Sie mit Docker-Compose eine schnelle API-Umgebung
Für Anfänger, um eine Anaconda-Umgebung aufzubauen. (Memo)
Implementieren Sie Custom Authorizer für die Firebase-Authentifizierung in Chalice
Holen Sie sich ein Zugriffstoken für die Pocket-API
Ich habe versucht, Firebase für Djangos Cache-Server zu verwenden
Erstellen Sie schnell einen API-Server mit Python + Falcon
Erstellen Sie einen API-Server, um den Betrieb der Front-Implementierung mit Python3 und Flask zu überprüfen