# 宇之然内容创作平台 - 安全模块 from datetime import datetime, timedelta from typing import Optional from jose import JWTError, jwt from fastapi.security import OAuth2PasswordBearer from fastapi import Depends, HTTPException, status from sqlalchemy.orm import Session from app.models import User from app.database import get_db import bcrypt # JWT配置 SECRET_KEY = "your-secret-key-here" # 生产环境应从环境变量读取 ALGORITHM = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES = 10080 # 7天 oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/auth/login") def verify_password(plain_password: str, hashed_password: str) -> bool: """验证密码(使用 bcrypt 直接比较)""" try: # 确保输入为字节 if isinstance(plain_password, str): plain_password = plain_password.encode('utf-8') if isinstance(hashed_password, str): hashed_password = hashed_password.encode('utf-8') return bcrypt.checkpw(plain_password, hashed_password) except Exception: return False def get_password_hash(password: str) -> str: """生成密码哈希(使用 bcrypt)""" if isinstance(password, str): password = password.encode('utf-8') hashed = bcrypt.hashpw(password, bcrypt.gensalt()) return hashed.decode('utf-8') def create_access_token(data: dict, expires_delta: Optional[timedelta] = None): """创建JWT token""" to_encode = data.copy() if expires_delta: expire = datetime.utcnow() + expires_delta else: expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) to_encode.update({"exp": expire}) encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) return encoded_jwt async def get_current_user( token: str = Depends(oauth2_scheme), db: Session = Depends(get_db) ) -> User: """获取当前用户""" credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="无效的认证凭据", headers={"WWW-Authenticate": "Bearer"}, ) try: payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) username: str = payload.get("sub") if username is None: raise credentials_exception except JWTError: raise credentials_exception user = db.query(User).filter(User.username == username).first() if user is None: raise credentials_exception return user async def get_current_active_user(current_user: User = Depends(get_current_user)): """获取活跃用户(简单检查)""" # 这里可以添加更多活跃性检查逻辑 return current_user async def get_current_admin_user(current_user: User = Depends(get_current_user)): """获取管理员用户""" if current_user.role != "admin": raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="权限不足,需要管理员角色" ) return current_user def create_audit_log( db: Session, user_id: int, action: str, username: str = "", resource_type: str = "", resource_id: int = None, details: str = "", ip_address: str = "", user_agent: str = "" ): """创建审计日志""" from app.models import AuditLog, User # 如果未提供 username,尝试从 user_id 查询 if not username: if user_id and user_id != 0: user = db.query(User).filter(User.id == user_id).first() if user: username = user.username if not username: username = "unknown" audit_log = AuditLog( user_id=user_id, username=username, action=action, resource_type=resource_type, resource_id=resource_id, details=details, ip_address=ip_address, user_agent=user_agent ) db.add(audit_log) db.commit()