FastAPI 全栈后端(四):认证与授权

创作者: 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 章。

🌟 欢迎大家来观看!

相关推荐
神奇的程序员3 小时前
我的软件冲进苹果商店下载榜前 50 了
前端
阳光是sunny4 小时前
别再被 worktree 绕晕了!AI 编程时代你必须掌握的 Git 隔离神器
前端·人工智能·后端
万少5 小时前
万少的博客 - 技术分享与解决方案
前端·javascript·后端
apocelipes7 小时前
常用编程语言和库的正则表达式性能对比
c语言·c++·python·性能优化·golang·开发工具和环境
尘世中一位迷途小书童7 小时前
用 Cesium 撸了一个森林火情监控大屏,弧线、粒子、发光效果都齐了
前端·javascript
IT_陈寒8 小时前
垃圾回收器选错了,我的Java服务内存炸了
前端·人工智能·后端
月光下的丝瓜8 小时前
Flutter 国内安装指南
前端·flutter
用户8356290780519 小时前
使用 Python 在 PDF 中创建与管理书签
后端·python
先吃饱再说9 小时前
JavaScript中`this` 的“千层套路”:从默认绑定到箭头函数的五种指向
javascript
玄星啊9 小时前
AI 编程的第 30 天,我怀念古法 Coding 了
前端·ai编程