
管理员
站长
- UID
- 1
- 积分
- 224402
- 余额
- 13 R
- Moe币
- 84883
- 在线时间
- 279 小时
- 注册时间
- 2025-12-28
- 最后登录
- 2026-11-13
|
"""用户认证:密码哈希(bcrypt) + JWT 签发/校验"""
from datetime import datetime, timedelta
from typing import Optional
import jwt
import bcrypt
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from sqlalchemy.orm import Session
from .config import settings
from .database import get_db, User
oauth2_scheme = OAuth2PasswordBearer(tokenUrl=f"{settings.api_prefix}/auth/login", auto_error=False)
def hash_password(password: str) -> str:
# bcrypt 限制 72 字节,先统一用 utf-8 bytes 截断
pwd_bytes = password.encode("utf-8")[:72]
return bcrypt.hashpw(pwd_bytes, bcrypt.gensalt()).decode("ascii")
def verify_password(plain: str, hashed: str) -> bool:
try:
return bcrypt.checkpw(plain.encode("utf-8")[:72], hashed.encode("ascii"))
except Exception:
return False
def create_access_token(subject: str, expires_delta: Optional[timedelta] = None) -> str:
expire = datetime.utcnow() + (expires_delta or timedelta(minutes=settings.access_token_expire_minutes))
payload = {"sub": str(subject), "exp": expire}
return jwt.encode(payload, settings.secret_key, algorithm=settings.algorithm)
def get_current_user(token: Optional[str] = Depends(oauth2_scheme), db: Session = Depends(get_db)) -> User:
cred_exception = HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="未登录或登录已过期")
if not token:
raise cred_exception
try:
data = jwt.decode(token, settings.secret_key, algorithms=[settings.algorithm])
uid = data.get("sub")
if not uid:
raise cred_exception
except jwt.PyJWTError:
raise cred_exception
user = db.query(User).filter(User.id == int(uid)).first()
if not user or not user.is_active:
raise cred_exception
return user
def get_current_admin(user: User = Depends(get_current_user)) -> User:
if user.role != "admin":
raise HTTPException(status_code=403, detail="需要管理员权限")
return user
|
|