Implement frontend user login
This commit is contained in:
74
backend/auth.py
Normal file
74
backend/auth.py
Normal file
@@ -0,0 +1,74 @@
|
||||
import os
|
||||
import json
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status, Header
|
||||
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
|
||||
from pydantic import BaseModel
|
||||
from passlib.context import CryptContext as PasswordContext
|
||||
from cryptography.fernet import Fernet, InvalidToken, InvalidSignature
|
||||
|
||||
from models import User
|
||||
|
||||
AUTH_ERROR = HTTPException(status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
password_context = PasswordContext(schemes=["bcrypt"], deprecated="auto")
|
||||
|
||||
SECRET_KEY = os.environ["SECRET_KEY"]
|
||||
crypto_context = Fernet(SECRET_KEY)
|
||||
|
||||
users_db = {
|
||||
"kai": {
|
||||
"username": "kai",
|
||||
"hashed_password": "$2b$12$mh5hSniE.1SqxK3IDDTIO.1jDKgU0KX2eZev3yFu4Z1ZUPXWMw2Xa",
|
||||
}
|
||||
}
|
||||
|
||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="auth/login")
|
||||
|
||||
|
||||
class UserInDb(User):
|
||||
hashed_password: str
|
||||
|
||||
|
||||
def get_current_user(token: str = Depends(oauth2_scheme)):
|
||||
try:
|
||||
token_data = json.loads(crypto_context.decrypt(token.encode()))
|
||||
except (InvalidToken, InvalidSignature):
|
||||
raise AUTH_ERROR
|
||||
return User(username=token_data["username"])
|
||||
|
||||
|
||||
auth_router = APIRouter()
|
||||
|
||||
|
||||
class TokenLoginResponse(BaseModel):
|
||||
access_token: str
|
||||
token_type: str
|
||||
|
||||
|
||||
@auth_router.post(
|
||||
"/login",
|
||||
tags=["auth"],
|
||||
responses={
|
||||
status.HTTP_400_BAD_REQUEST: {},
|
||||
status.HTTP_200_OK: {
|
||||
"model": TokenLoginResponse,
|
||||
},
|
||||
},
|
||||
)
|
||||
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
|
||||
|
||||
if form_data.username not in users_db:
|
||||
raise AUTH_ERROR
|
||||
|
||||
user = UserInDb(**users_db[form_data.username])
|
||||
|
||||
if not password_context.verify(form_data.password, user.hashed_password):
|
||||
raise AUTH_ERROR
|
||||
|
||||
token = crypto_context.encrypt(json.dumps({"username": user.username}).encode())
|
||||
|
||||
return {
|
||||
"access_token": token,
|
||||
"token_type": "bearer",
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
from fastapi import FastAPI, Response
|
||||
from pydantic import BaseSettings
|
||||
|
||||
from fastapi import FastAPI, Depends, Response
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from pydantic import BaseSettings, BaseModel
|
||||
|
||||
from models import User
|
||||
from auth import get_current_user, auth_router
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
@@ -11,6 +13,19 @@ class Settings(BaseSettings):
|
||||
settings = Settings()
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
app.include_router(
|
||||
auth_router,
|
||||
prefix="/auth",
|
||||
tags=["auth"]
|
||||
)
|
||||
|
||||
|
||||
@app.get("/test")
|
||||
async def read_test(user = Depends(get_current_user)):
|
||||
return {"name": user.username, "foo": "bar"}
|
||||
|
||||
|
||||
if settings.dev_mode:
|
||||
import httpx
|
||||
|
||||
|
||||
4
backend/models.py
Normal file
4
backend/models.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from pydantic import BaseModel
|
||||
|
||||
class User(BaseModel):
|
||||
username: str
|
||||
@@ -1,16 +1,22 @@
|
||||
anyio==3.4.0
|
||||
asgiref==3.4.1
|
||||
certifi==2021.10.8
|
||||
cffi==1.15.0
|
||||
charset-normalizer==2.0.9
|
||||
click==8.0.3
|
||||
cryptography==36.0.1
|
||||
fastapi==0.70.1
|
||||
h11==0.12.0
|
||||
httpcore==0.14.3
|
||||
httpx==0.21.1
|
||||
idna==3.3
|
||||
passlib==1.7.4
|
||||
pycparser==2.21
|
||||
pydantic==1.8.2
|
||||
python-multipart==0.0.5
|
||||
rfc3986==1.5.0
|
||||
six==1.16.0
|
||||
sniffio==1.2.0
|
||||
starlette==0.16.0
|
||||
typing-extensions==4.0.1
|
||||
uvicorn==0.16.0
|
||||
uvicorn==0.15.0
|
||||
|
||||
Reference in New Issue
Block a user