Files
WonderQ-Project/WonderQ-Admin/app/auth.py
duanshuwen d42f69bd47 feat: 新增用车需求服务及线索管理全功能
- 新增后台用车服务配置模块,支持维护服务简介、优势与使用流程
- 新增需求线索管理页面,支持筛选、查看与更新用车线索状态
- 新增小程序用车需求页面,优化登录路径与回跳逻辑
- 优化车型卡片跳转与用车需求提交功能
- 新增服务端API与数据处理逻辑,完善权限校验
- 更新全站配置与API文档,新增相关测试用例
2026-08-22 21:48:08 +08:00

114 lines
4.3 KiB
Python

from datetime import datetime, timedelta, timezone
import bcrypt
import jwt
from fastapi import Depends, HTTPException, Request, status
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from sqlalchemy.orm import Session
from .config import get_settings
from .database import get_db
from .models import AdminUser, Customer
bearer = HTTPBearer(auto_error=False)
def verify_password(password: str, password_hash: str) -> bool:
return bcrypt.checkpw(password.encode("utf-8"), password_hash.encode("utf-8"))
def hash_password(password: str, rounds: int = 12) -> str:
return bcrypt.hashpw(password.encode("utf-8"), bcrypt.gensalt(rounds)).decode("utf-8")
def create_token(user: AdminUser) -> str:
settings = get_settings()
now = datetime.now(timezone.utc)
payload = {
"typ": "admin",
"sub": user.id,
"email": user.email,
"role": user.role,
"iat": now,
"exp": now + timedelta(hours=settings.jwt_expires_hours),
}
return jwt.encode(payload, settings.jwt_secret, algorithm="HS256")
def create_customer_token(customer: Customer) -> str:
settings = get_settings()
now = datetime.now(timezone.utc)
payload = {
"typ": "customer",
"sub": customer.id,
"iat": now,
"exp": now + timedelta(hours=settings.customer_jwt_expires_hours),
}
return jwt.encode(payload, settings.jwt_secret, algorithm="HS256")
def require_admin(
request: Request,
credentials: HTTPAuthorizationCredentials | None = Depends(bearer),
db: Session = Depends(get_db),
) -> AdminUser:
if credentials is None:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="请先登录后台")
try:
payload = jwt.decode(credentials.credentials, get_settings().jwt_secret, algorithms=["HS256"])
except jwt.PyJWTError as exc:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="请先登录后台") from exc
if payload.get("typ", "admin") != "admin":
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="请先登录后台")
user_id = payload.get("sub")
user = db.get(AdminUser, user_id) if user_id else None
if not user or not user.isActive:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="请先登录后台")
request.state.actor_id = user.id
return user
def require_customer(
request: Request,
credentials: HTTPAuthorizationCredentials | None = Depends(bearer),
db: Session = Depends(get_db),
) -> Customer:
if credentials is None:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="请先登录")
try:
payload = jwt.decode(credentials.credentials, get_settings().jwt_secret, algorithms=["HS256"])
except jwt.PyJWTError as exc:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="请先登录") from exc
if payload.get("typ") != "customer":
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="请先登录")
customer_id = payload.get("sub")
customer = db.get(Customer, customer_id) if customer_id else None
if not customer:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="请先登录")
request.state.actor_id = customer.id
return customer
def optional_customer(
request: Request,
credentials: HTTPAuthorizationCredentials | None = Depends(bearer),
db: Session = Depends(get_db),
) -> Customer | None:
if credentials is None:
return None
try:
payload = jwt.decode(credentials.credentials, get_settings().jwt_secret, algorithms=["HS256"])
except jwt.PyJWTError as exc:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="请先登录") from exc
if payload.get("typ") != "customer":
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="请先登录")
customer_id = payload.get("sub")
customer = db.get(Customer, customer_id) if customer_id else None
if not customer:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="请先登录")
request.state.actor_id = customer.id
return customer
def get_actor_id(request: Request) -> str | None:
return getattr(request.state, "actor_id", None)