创作者: Yardon | GitHub: github.com/YardonYan | 版本: v1.0 |
认证 vs 授权:澄清概念
- 认证 (Authentication):你是谁?------登录凭证(密码、JWT)
- 授权 (Authorization):你能做什么?------权限检查(管理员 vs 普通用户)
认证像身份证(证明你是谁),授权像工作证(决定你能进哪个房间)。
密码安全存储
python
from passlib.context import CryptContext
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def hash_password(password: str) -> str:
return pwd_context.hash(password)
def verify_password(plain: str, hashed: str) -> bool:
return pwd_context.verify(plain, hashed)
# bcrypt 会自动加盐,一次 hash 的结果每次都不同:
hash1 = hash_password("secret") # $2b$12$...
hash2 = hash_password("secret") # $2b$12$...(不同!)
verify_password("secret", hash1) # True
JWT 原理与实现
JWT(JSON Web Token)把用户信息存在 Token 本身,服务器不需要存:
header.payload.signature
python
from datetime import datetime, timedelta
from jose import JWTError, jwt
SECRET_KEY = "your-secret-key-change-this"
ALGORITHM = "HS256"
def create_access_token(data: dict, expires_delta: timedelta = None):
to_encode = data.copy()
expire = datetime.utcnow() + (expires_delta or timedelta(hours=24))
to_encode.update({"exp": expire})
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
def verify_token(token: str) -> dict:
try:
return jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
except JWTError:
raise HTTPException(status_code=401, detail="无效的 Token")
OAuth2 密码模式
python
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from fastapi import Depends
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/token")
@app.post("/auth/token")
async def login(form: OAuth2PasswordRequestForm = Depends()):
user = await authenticate(form.username, form.password)
if not user:
raise HTTPException(status_code=401, detail="用户名或密码错误")
access_token = create_access_token({"sub": user.username, "role": user.role})
return {"access_token": access_token, "token_type": "bearer"}
# 在需要认证的路由中使用
@app.get("/users/me")
async def read_current_user(token: str = Depends(oauth2_scheme)):
payload = verify_token(token)
username = payload.get("sub")
user = await get_user_by_username(username)
return user
依赖注入实现权限控制
python
async def get_current_user(token: str = Depends(oauth2_scheme)):
payload = verify_token(token)
username = payload.get("sub")
user = await get_user_by_username(username)
if not user:
raise HTTPException(status_code=404, detail="用户不存在")
return user
# 可选:检查管理员权限
async def require_admin(user: User = Depends(get_current_user)):
if user.role != "admin":
raise HTTPException(status_code=403, detail="需要管理员权限")
return user
# 路由中使用
@app.delete("/users/{user_id}", dependencies=[Depends(require_admin)])
async def delete_user(user_id: int):
...
角色与权限系统
python
from enum import Enum
class Role(str, Enum):
ADMIN = "admin"
MODERATOR = "moderator"
USER = "user"
class Permission(str, Enum):
READ = "read"
WRITE = "write"
DELETE = "delete"
ROLE_PERMISSIONS = {
Role.ADMIN: [Permission.READ, Permission.WRITE, Permission.DELETE],
Role.MODERATOR: [Permission.READ, Permission.WRITE],
Role.USER: [Permission.READ],
}
def has_permission(user: User, permission: Permission) -> bool:
return permission in ROLE_PERMISSIONS[Role(user.role)]
本章小结
认证用 JWT(无状态、可跨域)、依赖注入做权限控制(可组合、可测试)、bcrypt 存密码(安全)。
📌 创作者: Yardon | 🏠 个人网站: GlimmerAI.top
📖 本章是「FastAPI 全栈后端」系列的第 4 章。
🌟 欢迎大家来观看!