2026-05-30 07:23:33 +08:00
|
|
|
|
"""
|
|
|
|
|
|
认证路由模块
|
|
|
|
|
|
|
|
|
|
|
|
职责:
|
|
|
|
|
|
处理用户认证相关接口,URL 前缀为 /api/auth。
|
|
|
|
|
|
包括:登录、获取当前用户信息、登出、绑定微信 OpenID。
|
|
|
|
|
|
"""
|
|
|
|
|
|
import json
|
|
|
|
|
|
|
2026-05-15 13:40:58 +08:00
|
|
|
|
from fastapi import APIRouter, Depends, Header
|
2026-05-26 11:36:57 +08:00
|
|
|
|
from pydantic import BaseModel
|
2026-05-14 23:28:09 +08:00
|
|
|
|
from sqlalchemy.orm import Session
|
2026-05-14 13:51:06 +08:00
|
|
|
|
|
2026-05-15 12:05:18 +08:00
|
|
|
|
from backend.app.api.deps import get_auth_service, get_current_user
|
2026-05-14 23:28:09 +08:00
|
|
|
|
from backend.app.db import get_db_session
|
2026-05-14 13:51:06 +08:00
|
|
|
|
from backend.app.schemas.auth import LoginRequest
|
|
|
|
|
|
from backend.app.schemas.common import success_payload
|
|
|
|
|
|
from backend.app.services.auth_service import AuthService
|
2026-05-26 11:36:57 +08:00
|
|
|
|
from backend.app.services.wechat_notification_service import wechat_notification_service
|
2026-05-14 13:51:06 +08:00
|
|
|
|
|
|
|
|
|
|
router = APIRouter(prefix="/api/auth", tags=["auth"])
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-05-26 11:36:57 +08:00
|
|
|
|
class BindOpenIdRequest(BaseModel):
|
2026-05-30 07:23:33 +08:00
|
|
|
|
"""绑定微信 OpenID 请求体"""
|
2026-05-26 11:36:57 +08:00
|
|
|
|
open_id: str
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-05-14 13:51:06 +08:00
|
|
|
|
@router.post("/login")
|
2026-05-14 23:28:09 +08:00
|
|
|
|
def login(
|
2026-05-30 07:23:33 +08:00
|
|
|
|
payload: LoginRequest, # 登录请求体,包含用户名、密码、角色类型
|
|
|
|
|
|
auth_service: AuthService = Depends(get_auth_service), # 注入认证服务
|
|
|
|
|
|
session: Session = Depends(get_db_session), # 注入数据库会话
|
2026-05-14 23:28:09 +08:00
|
|
|
|
) -> dict:
|
2026-05-30 07:23:33 +08:00
|
|
|
|
"""用户登录接口
|
|
|
|
|
|
|
|
|
|
|
|
用途:验证用户名和密码,返回 JWT Token。
|
|
|
|
|
|
请求参数:LoginRequest(username、password、role_type)。
|
|
|
|
|
|
返回值:登录结果,包含 token 等认证信息。
|
|
|
|
|
|
权限要求:无需认证(公开接口)。
|
|
|
|
|
|
"""
|
2026-05-14 23:28:09 +08:00
|
|
|
|
return success_payload(auth_service.login(payload.username, payload.password, payload.role_type, session))
|
2026-05-14 13:51:06 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("/me")
|
|
|
|
|
|
def me(
|
2026-05-30 07:23:33 +08:00
|
|
|
|
current_user: dict = Depends(get_current_user), # 从 JWT Token 解析当前用户
|
2026-05-14 13:51:06 +08:00
|
|
|
|
) -> dict:
|
2026-05-30 07:23:33 +08:00
|
|
|
|
"""获取当前登录用户信息
|
|
|
|
|
|
|
|
|
|
|
|
用途:返回当前已登录用户的详细信息(角色、权限等)。
|
|
|
|
|
|
请求参数:无(通过请求头 Authorization 传递 Token)。
|
|
|
|
|
|
返回值:当前用户信息字典。
|
|
|
|
|
|
权限要求:必须已登录(携带有效 Token)。
|
|
|
|
|
|
"""
|
2026-05-15 12:05:18 +08:00
|
|
|
|
return success_payload(current_user)
|
2026-05-14 13:51:06 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("/logout")
|
2026-05-15 12:05:18 +08:00
|
|
|
|
def logout(
|
2026-05-30 07:23:33 +08:00
|
|
|
|
authorization: str | None = Header(default=None), # 请求头中的 Authorization 字段
|
|
|
|
|
|
auth_service: AuthService = Depends(get_auth_service), # 注入认证服务
|
2026-05-15 12:05:18 +08:00
|
|
|
|
) -> dict:
|
2026-05-30 07:23:33 +08:00
|
|
|
|
"""用户登出接口
|
|
|
|
|
|
|
|
|
|
|
|
用途:使当前 Token 失效,完成登出。
|
|
|
|
|
|
请求参数:通过请求头 Authorization 传递 Bearer Token。
|
|
|
|
|
|
返回值:登出结果。
|
|
|
|
|
|
权限要求:无需严格校验,但需传递 Token。
|
|
|
|
|
|
"""
|
2026-05-15 12:05:18 +08:00
|
|
|
|
token = (authorization or "").removeprefix("Bearer").strip()
|
|
|
|
|
|
return success_payload(auth_service.logout(token))
|
2026-05-26 11:36:57 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("/bind-openid")
|
|
|
|
|
|
def bind_openid(
|
2026-05-30 07:23:33 +08:00
|
|
|
|
payload: BindOpenIdRequest, # 绑定请求体,包含微信 OpenID
|
|
|
|
|
|
session: Session = Depends(get_db_session), # 注入数据库会话
|
|
|
|
|
|
current_user: dict = Depends(get_current_user), # 当前登录用户
|
2026-05-26 11:36:57 +08:00
|
|
|
|
) -> dict:
|
2026-05-30 07:23:33 +08:00
|
|
|
|
"""绑定微信 OpenID 接口
|
|
|
|
|
|
|
|
|
|
|
|
用途:将当前用户的账号与微信 OpenID 绑定,用于微信消息通知。
|
|
|
|
|
|
请求参数:BindOpenIdRequest(open_id - 微信用户的 OpenID)。
|
|
|
|
|
|
返回值:绑定结果 {"success": true}。
|
|
|
|
|
|
权限要求:必须已登录。
|
|
|
|
|
|
"""
|
2026-05-26 11:36:57 +08:00
|
|
|
|
wechat_notification_service.bind_open_id(session, current_user["user_id"], payload.open_id)
|
|
|
|
|
|
return success_payload({"success": True})
|