Criando Endpoints de Auth
Agora precisamos mapear a função de geração e validação de tokens na API, expondo a
URL /token
para que possamos gerar um token para um usuário.
EDITE dundie/routes/auth.py
from datetime import timedelta
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordRequestForm
from dundie.auth import (
RefreshToken,
Token,
User,
authenticate_user,
create_access_token,
create_refresh_token,
get_user,
validate_token,
)
from dundie.config import settings
ACCESS_TOKEN_EXPIRE_MINUTES = settings.security.access_token_expire_minutes # pyright: ignore
REFRESH_TOKEN_EXPIRE_MINUTES = settings.security.refresh_token_expire_minutes # pyright: ignore
router = APIRouter()
@router.post("/token", response_model=Token)
async def login_for_access_token(
form_data: OAuth2PasswordRequestForm = Depends(),
):
user = authenticate_user(get_user, form_data.username, form_data.password)
if not user or not isinstance(user, User):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"},
)
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) # pyright: ignore
access_token = create_access_token(
data={"sub": user.username, "fresh": True},
expires_delta=access_token_expires,
)
refresh_token_expires = timedelta(minutes=REFRESH_TOKEN_EXPIRE_MINUTES) # pyright: ignore
refresh_token = create_refresh_token(
data={"sub": user.username}, expires_delta=refresh_token_expires
)
return {
"access_token": access_token,
"refresh_token": refresh_token,
"token_type": "bearer",
}
@router.post("/refresh_token", response_model=Token)
async def refresh_token(form_data: RefreshToken):
user = await validate_token(token=form_data.refresh_token)
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) # pyright: ignore
access_token = create_access_token(
data={"sub": user.username, "fresh": False},
expires_delta=access_token_expires,
)
refresh_token_expires = timedelta(minutes=REFRESH_TOKEN_EXPIRE_MINUTES) # pyright: ignore
refresh_token = create_refresh_token(
data={"sub": user.username}, expires_delta=refresh_token_expires
)
return {
"access_token": access_token,
"refresh_token": refresh_token,
"token_type": "bearer",
}
E agora vamos adicionar essas URLS ao router principal
EDITE dundie/routes/__init__.py
No topo na linha 3
from .auth import router as auth_router
E depois na linha 9
main_router.include_router(auth_router, tags=["auth"])
Vamos testar a aquisição de um token via curl. (ou pode utilizar algum outro cliente HTTP de sua preferencia como o Imsomnia ou Postman)
curl -X 'POST' \
'http://localhost:8000/token' \
-H 'accept: application/json' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'username=michael-scott&password=boss123'
passe como parametro os dados de um usuário que tenha criado via linha de comando.
Resposta:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImZyZXNoIjp0cnVlLCJleHAiOjE2Njg2Mjg0NjgsInNjb3BlIjoiYWNjZXNzX3Rva2VuIn0.P-F3onD2vFFIld_ls1irE9rOgLNk17SNDASls31lgkU",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImV4cCI6MTY2ODY2MjY2OCwic2NvcGUiOiJyZWZyZXNoX3Rva2VuIn0.AWV8QtySYmcukxTgTa9GedLK00o6wrbyMt9opW42eyQ",
"token_type": "bearer"
}
agora sim já conseguimos gerar o token, só falta proteger as URLs -->