共计 1912 个字符,预计需要花费 5 分钟才能阅读完成。
在实现用户身份验证后,我们常常还需对不同用户角色或权限范围做更细致的限制。本节将介绍如何在 FastAPI 中基于 OAuth2 实现权限作用域控制。
一、理解作用域(Scopes)
OAuth2 支持作用域,用于指定访问权限范围,例如:
read:user:读取用户信息write:user:修改用户信息
二、定义 OAuth2PasswordBearer 带作用域
from fastapi.security import OAuth2PasswordBearer
oauth2_scheme = OAuth2PasswordBearer(
tokenUrl="login",
scopes={
"me": "Read information about the current user.",
"admin": "Admin-only access.",
}
)
三、修改 token 生成函数,添加作用域
def create_access_token(data: dict, scopes: list = []):
to_encode = data.copy()
to_encode.update({"scopes": scopes})
expire = datetime.utcnow() + timedelta(minutes=60)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
四、验证 token 并校验作用域
from fastapi import Security, HTTPException
from fastapi.security import SecurityScopes
def get_current_user(
security_scopes: SecurityScopes,
token: str = Depends(oauth2_scheme),
db: Session = Depends(get_db)
):
credentials_exception = HTTPException(
status_code=401,
detail="Could not validate credentials",
headers={"WWW-Authenticate": f'Bearer scope="{security_scopes.scope_str}"'}
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username = payload.get("sub")
token_scopes = payload.get("scopes", [])
if username is None:
raise credentials_exception
except JWTError:
raise credentials_exception
for scope in security_scopes.scopes:
if scope not in token_scopes:
raise HTTPException(
status_code=403,
detail="Not enough permissions",
headers={"WWW-Authenticate": f'Bearer scope="{security_scopes.scope_str}"'},
)
user = db.query(User).filter(User.email == username).first()
if user is None:
raise credentials_exception
return user
五、限制接口权限
from fastapi import APIRouter
router = APIRouter()
@router.get("/admin/dashboard")
def read_admin_dashboard(current_user: User = Security(get_current_user, scopes=["admin"])
):
return {"msg": "Welcome, Admin!", "user": current_user.email}
六、使用方式
- 登录时为管理员用户生成包含
adminscope 的 token - 请求接口时附上 token,FastAPI 自动校验作用域是否满足
七、总结
作用域机制使 FastAPI 更好地支持细粒度权限控制。通过 SecurityScopes 与 Security 组合,我们可以快速为路由设置访问条件。下一节我们将讲解如何编写中间件,对全局请求统一拦截处理。
正文完