FastAPI est pratique. Je l'utilise personnellement comme un framework qui facilite la création d'un serveur API. Cette fois, nous ajouterons une fonction d'authentification à l'API Fast.
** Attention **: une configuration telle que l'installation de FastAPI et Firebase n'est pas mentionnée ici comme une condition préalable.
Je pense qu'il y a beaucoup de demande pour identifier et authentifier l'utilisateur qui a demandé le serveur et contrôler l'autorisation appropriée pour la ressource demandée. Ici, nous allons implémenter l'authentification au porteur, qui peut être facilement implémentée en l'ajoutant simplement à l'en-tête HTTP.
[Qiita] "À propos de l'authentification du porteur"
Peut être spécifié comme un schéma dans l'en-tête HTTP Authorization, tel que
Authorization: Bearer <token>
. Le format du jeton est spécifié dans le format token68.
Puisqu'il est difficile d'implémenter l'émission et la vérification du «token» par vous-même, nous utiliserons Firebase cette fois.
L'image complète de l'authentification du support à l'aide de Firebase est illustrée.
token
token
token
pour le valider.
Si la vérification réussit, l'identification / l'authentification de l'utilisateur est terminée.Implémenter la fonctionnalité d'authentification à l'aide du SDK Firebase Admin
Obtenez un compte Firebase à l'avance. Tout d'abord, ouvrez la console du projet (https://console.firebase.google.com/u/0/)
Ouvrez les paramètres à partir de l'icône d'engrenage en haut à droite
Obtenez la clé privée sous forme de fichier JSON à partir du bouton en bas de l'onglet Comptes de service. Ici, enregistrez-le sous account_key.json
.
$ pip install firebase_admin
Tout d'abord, préparez un point de terminaison simple et créez un serveur API minimum.
main.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/api/")
async def hello():
return {"msg":"Hello, this is API server"}
Configurons un serveur de test avec uvicorn
$ uvicorn main:app --port 8001 --reload
Frappons le serveur API à titre d'essai (le navigateur Web est également OK)
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
Vous devez d'abord extraire le token
de l'en-tête Authorization. FastAPI est pratique car vous pouvez également valider l'en-tête d'authentification de la demande.
[FastAPI] Query Parameters and String Validations
[Qiita] Acquisition de jetons d'authentification Firebase avec Python et vérification de jetons avec Fast API
Ensuite, vérifiez token
. Le code ci-dessus définit ce qu'il faut faire si «token» n'existe pas et n'est pas valide. Le contenu de la réponse à l'erreur est conforme à la RFC 6750 qui définit l'authentification du support. Lancez simplement HTTPExeption
et l'API rapide le récupérera et générera une réponse, donc c'est facile.
Documentation officielle de Firebase
Firebase Admin Python SDK
[[Qiita] Pour implémenter un schéma de support conforme à la RFC 6750](https://qiita.com/uasi/items/cfb60588daa18c2ec6f5#rfc-6750-%E3%81%AB%E6%BA%96%E6 % 8B% A0% E3% 81% 97% E3% 81% 9F-porteur-% 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)
** Attention **: Avec HTTPBearer (auto_error = True)
(par défaut), pour les requêtes sans token
PS > curl http://localhost:8001/api/me
curl : {"detail":"Not authenticated"}
PS > $error[0].exception
Le serveur distant a renvoyé une erreur: (403)Indisponible
Et Fast API générera une gestion des exceptions + réponse sans autorisation.
Ajoutez un point de terminaison d'API qui nécessite une authentification utilisateur.
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
est l'identifiant de l'utilisateur qui s'est connecté à Firebase, et peut identifier non seulement l'e-mail et le mot de passe, mais également les utilisateurs authentifiés par divers services tels que Twitter et Google.
Frappons réellement l'API du client et voyons la réponse.
token
Sélectionnez un projet dans Firebase Console et copiez-le dans Paramètres> Général.
En supposant que l'utilisateur (e-mail et mot de passe) est déjà enregistré dans le projet
POST
https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=${API_KEY}
--Body: Informations requises pour la connexion écrites en JSON{
"email":"[email protected]",
"password":"your password",
"returnSecureToken":true
}
[Firebase] Auth REST API - Documentation officielle
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...
La réponse est également JSON et utilise la valeur de idToken
pour l'authentification du porteur.
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":...
token
illégalEssayez de jouer avec la valeur de token
et passez-la
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