fastapi_jwt/
├── main.py
├── database.py
├── models.py
├── schemas.py
├── auth.py
├── create_db.py
├── requirements.txt
└── test.db # criado automaticamente
pip install -r requirements.txt
pip install fastapi uvicorn sqlalchemy pydantic[email] python-jose passlib[bcrypt] python-multipart
database.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, declarative_base
DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
SessionLocal = sessionmaker(bind=engine, autoflush=False, autocommit=False)
Base = declarative_base()
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
models.py
from sqlalchemy import Column, Integer, String
from database import Base
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
name = Column(String)
email = Column(String, unique=True, index=True)
password = Column(String)
schemas.py
from pydantic import BaseModel, EmailStr
class UserCreate(BaseModel):
name: str
email: EmailStr
password: str
class UserResponse(BaseModel):
id: int
name: str
email: EmailStr
class Config:
from_attributes = True
class Token(BaseModel):
access_token: str
token_type: str
auth.py
from datetime import datetime, timedelta
from jose import JWTError, jwt
from passlib.context import CryptContext
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from sqlalchemy.orm import Session
from models import User
from database import get_db
SECRET_KEY = "sua_chave_secreta"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="login")
def hash_password(password: str):
return pwd_context.hash(password)
def verify_password(plain_password, hashed_password):
return pwd_context.verify(plain_password, hashed_password)
def create_access_token(data: dict, expires_delta: timedelta = timedelta(minutes=30)):
to_encode = data.copy()
expire = datetime.utcnow() + expires_delta
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
def get_current_user(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Credenciais inválidas",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
except JWTError:
raise credentials_exception
user = db.query(User).filter(User.name == username).first()
if user is None:
raise credentials_exception
return user
main.py
from fastapi import FastAPI, Depends, HTTPException, status
from sqlalchemy.orm import Session
from fastapi.security import OAuth2PasswordRequestForm
from database import get_db
from models import User
from schemas import UserCreate, UserResponse, Token
from auth import hash_password, verify_password, create_access_token, get_current_user
app = FastAPI(title="API com JWT + SQLite", version="1.0.0")
@app.post("/register", response_model=Token)
def register(user: UserCreate, db: Session = Depends(get_db)):
db_user = db.query(User).filter(User.name == user.name).first()
if db_user:
raise HTTPException(status_code=400, detail="Nome de usuário já existe")
hashed = hash_password(user.password)
new_user = User(name=user.name, email=user.email, password=hashed)
db.add(new_user)
db.commit()
db.refresh(new_user)
access_token = create_access_token(data={"sub": new_user.name})
return {"access_token": access_token, "token_type": "bearer"}
@app.post("/login", response_model=Token)
def login(form_data: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(get_db)):
user = db.query(User).filter(User.name == form_data.username).first()
if not user or not verify_password(form_data.password, user.password):
raise HTTPException(status_code=401, detail="Credenciais inválidas")
token = create_access_token(data={"sub": user.name})
return {"access_token": token, "token_type": "bearer"}
@app.get("/me", response_model=UserResponse)
def read_current_user(current_user: User = Depends(get_current_user)):
return current_user
create_db.py
from database import Base, engine
from models import User
Base.metadata.create_all(bind=engine)
requirements.txt
fastapi
uvicorn
sqlalchemy
pydantic[email]
passlib[bcrypt]==1.7.4
bcrypt==3.2.0
python-jose
python-multipart
python create_db.py
uvicorn main:app --reload
POST /register
— cria um usuário e já retorna tokenPOST /login
— autentica e retorna token JWTGET /me
— retorna dados do usuário logado (token obrigatório)/me
no Swagger UI:/login
e envie:username
: nome de usuáriopassword
: senha cadastradaaccess_token
da resposta.Bearer <token>
./me
— agora está autenticado!.bat
para criar a estrutura automaticamente:setup_projeto.bat
:@echo off
mkdir fastapi_jwt
cd fastapi_jwt
:: Criação dos arquivos principais
type nul > main.py
type nul > auth.py
type nul > database.py
type nul > models.py
type nul > schemas.py
type nul > create_db.py
type nul > requirements.txt
:: Dependências do projeto
echo fastapi>>requirements.txt
echo uvicorn>>requirements.txt
echo sqlalchemy>>requirements.txt
echo "pydantic[email]">>requirements.txt
echo passlib[bcrypt]==1.7.4>>requirements.txt
echo bcrypt==3.2.0>>requirements.txt
echo python-jose>>requirements.txt
echo python-multipart>>requirements.txt
Exemplo real: o botão “Entrar com Google” ou “Entrar com GitHub” usa OAuth2 por trás.
<HEADER>.<PAYLOAD>.<SIGNATURE>
O JWT é frequentemente usado como formato do token dentro do fluxo OAuth2.
from fastapi.security import OAuth2PasswordBearer
from jose import jwt
jwt.encode({...}, SECRET_KEY, algorithm="HS256")