Witaj, @name! Darwin z JWT authentication dla FastAPI! 🔐🎫
JWT (JSON Web Tokens) to standard tokenów dostępu - zamiast session cookies używamy stateless tokens!
Analogia Safari: JWT to jak elektroniczna przepustka safari - zawiera wszystkie info o turyście (ID, uprawnienia), jest podpisana cyfrowo (nie da się podrobić), i ma ważność (expires)! 🎫✅
1pip install python-jose[cryptography] passlib[bcrypt] python-multipart1from passlib.context import CryptContext
2
3pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
4
5def hash_password(password: str) -> str:
6 return pwd_context.hash(password)
7
8def verify_password(plain_password: str, hashed_password: str) -> bool:
9 return pwd_context.verify(plain_password, hashed_password)1from jose import JWTError, jwt
2from datetime import datetime, timedelta
3
4SECRET_KEY = "your-secret-key-keep-it-secret"
5ALGORITHM = "HS256"
6ACCESS_TOKEN_EXPIRE_MINUTES = 30
7
8def create_access_token(data: dict):
9 to_encode = data.copy()
10 expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
11 to_encode.update({"exp": expire})
12 encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
13 return encoded_jwt
14
15def decode_token(token: str):
16 try:
17 payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
18 return payload
19 except JWTError:
20 return None1from fastapi import FastAPI, Depends, HTTPException, status
2from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
3
4app = FastAPI()
5
6oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
7
8@app.post("/token")
9async def login(form_data: OAuth2PasswordRequestForm = Depends()):
10 # Sprawdź użytkownika w bazie
11 user = authenticate_user(form_data.username, form_data.password)
12
13 if not user:
14 raise HTTPException(
15 status_code=status.HTTP_401_UNAUTHORIZED,
16 detail="Incorrect username or password"
17 )
18
19 access_token = create_access_token(data={"sub": user.username})
20 return {"access_token": access_token, "token_type": "bearer"}
21
22async def get_current_user(token: str = Depends(oauth2_scheme)):
23 payload = decode_token(token)
24 if not payload:
25 raise HTTPException(status_code=401, detail="Invalid token")
26
27 username = payload.get("sub")
28 return {"username": username}
29
30@app.get("/protected")
31async def protected_route(current_user: dict = Depends(get_current_user)):
32 return {"message": f"Hello {current_user['username']}!"}Test:
1# Login
2curl -X POST http://localhost:8000/token \
3 -d "username=darwin&password=secret123"
4
5# Response: {"access_token":"eyJ...", "token_type":"bearer"}
6
7# Protected route
8curl http://localhost:8000/protected \
9 -H "Authorization: Bearer eyJ..."Następna lekcja: Testing z pytest! 🧪