refactor(structure): reorganize app layout

BREAKING CHANGE: root backend/frontend directories and old run/manage entrypoints were removed. Use apps/backend, apps/frontend, and python main.py commands instead.
This commit is contained in:
2026-05-03 16:43:11 +08:00
parent 7e8852877e
commit d4d6f87730
112 changed files with 347 additions and 1596 deletions
+127
View File
@@ -0,0 +1,127 @@
"""
JWT 认证工具模块
用于生成和验证网站登录的 JWT Token
注意:这与打卡业务的 authorization token 是分开的
"""
import jwt
from datetime import datetime, timedelta
from typing import Optional, Dict, Any
from backend.config import settings
import logging
logger = logging.getLogger(__name__)
# JWT 配置
JWT_SECRET_KEY = settings.SECRET_KEY # 使用现有的 SECRET_KEY
JWT_ALGORITHM = "HS256"
JWT_EXPIRATION_DAYS = 21 # JWT 有效期:21天
class JWTManager:
"""JWT 管理器"""
@staticmethod
def create_access_token(user_id: int, user_alias: str) -> str:
"""
创建访问令牌
Args:
user_id: 用户 ID
user_alias: 用户别名
Returns:
JWT token 字符串
"""
now = datetime.utcnow()
exp = now + timedelta(days=JWT_EXPIRATION_DAYS)
payload = {
"user_id": user_id,
"alias": user_alias,
"iat": now, # Issued At - 签发时间
"exp": exp, # Expiration Time - 过期时间
"type": "access" # Token 类型
}
token = jwt.encode(payload, JWT_SECRET_KEY, algorithm=JWT_ALGORITHM)
logger.info(f"为用户 {user_alias}(ID: {user_id}) 创建 JWT,过期时间: {exp}")
return token
@staticmethod
def verify_token(token: str) -> Dict[str, Any]:
"""
验证并解码 JWT token
Args:
token: JWT token 字符串
Returns:
解码后的 payload 字典
Raises:
jwt.ExpiredSignatureError: Token 已过期
jwt.InvalidTokenError: Token 无效
"""
try:
payload = jwt.decode(token, JWT_SECRET_KEY, algorithms=[JWT_ALGORITHM])
# 验证 token 类型
if payload.get("type") != "access":
raise jwt.InvalidTokenError("Token 类型不正确")
return payload
except jwt.ExpiredSignatureError:
logger.warning("JWT Token 已过期")
raise
except jwt.InvalidTokenError as e:
logger.warning(f"JWT Token 无效: {str(e)}")
raise
except Exception as e:
logger.error(f"验证 JWT Token 时发生错误: {str(e)}")
raise jwt.InvalidTokenError(f"Token 验证失败: {str(e)}")
@staticmethod
def get_user_id_from_token(token: str) -> Optional[int]:
"""
从 JWT token 中提取用户 ID(不验证过期)
Args:
token: JWT token 字符串
Returns:
用户 ID 或 None
"""
try:
# decode 时设置 verify=False 跳过过期验证
payload = jwt.decode(
token,
JWT_SECRET_KEY,
algorithms=[JWT_ALGORITHM],
options={"verify_exp": False}
)
return payload.get("user_id")
except Exception as e:
logger.error(f"从 Token 提取用户 ID 失败: {str(e)}")
return None
@staticmethod
def is_token_expired(token: str) -> bool:
"""
检查 token 是否过期(不抛出异常)
Args:
token: JWT token 字符串
Returns:
True 表示已过期,False 表示未过期
"""
try:
JWTManager.verify_token(token)
return False
except jwt.ExpiredSignatureError:
return True
except jwt.InvalidTokenError:
return True