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.
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.
Das gesamte Bild der Bearer-Authentifizierung mit Firebase ist dargestellt.
Implementieren Sie die Authentifizierungsfunktion mithilfe des Firebase Admin SDK
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
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
.
$ pip install firebase_admin
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"}
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.
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.
Lassen Sie uns tatsächlich die API vom Client aus treffen und die Antwort sehen.
Wählen Sie ein Projekt unter Firebase Console aus und kopieren Sie es unter Einstellungen> Allgemein.
Angenommen, der Benutzer (E-Mail & Passwort) ist bereits im Projekt registriert
POST
https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=${API_KEY}
--Body: Informationen, die für die Anmeldung in JSON erforderlich sind{
"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.
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":...
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."}
PS > curl http://localhost:8001/api/me
curl : {"detail":"Bearer authentication required"}
Recommended Posts