mirror of
https://github.com/Cccc-owo/CheckInApp.git
synced 2026-06-17 14:06:28 +00:00
feat: implement JWT auth and optimize token validation
- Separate JWT login (21d) from check-in token - Unify check-in token validation with verify_checkin_authorization() - Update API docs for dual-token architecture
This commit is contained in:
@@ -188,20 +188,20 @@ async def get_system_stats(
|
||||
).count()
|
||||
|
||||
# Token 即将过期的用户数(7天内)
|
||||
from backend.services.auth_service import AuthService
|
||||
|
||||
current_timestamp = int(datetime.now().timestamp())
|
||||
expiring_soon_timestamp = current_timestamp + (7 * 24 * 60 * 60) # 7天后
|
||||
|
||||
expiring_users = 0
|
||||
for user in db.query(User).all():
|
||||
if user.jwt_exp and user.jwt_exp != "0":
|
||||
try:
|
||||
exp_timestamp = int(user.jwt_exp)
|
||||
if current_timestamp < exp_timestamp < expiring_soon_timestamp:
|
||||
expiring_users += 1
|
||||
except ValueError:
|
||||
# jwt_exp 格式不正确,跳过此用户
|
||||
logger.debug(f"用户 {user.id} 的 jwt_exp 格式不正确: {user.jwt_exp}")
|
||||
continue
|
||||
# 使用统一的验证方法
|
||||
result = AuthService.verify_checkin_authorization(user)
|
||||
|
||||
if result["is_valid"]:
|
||||
exp_timestamp = result.get("expires_at")
|
||||
if exp_timestamp and current_timestamp < exp_timestamp < expiring_soon_timestamp:
|
||||
expiring_users += 1
|
||||
|
||||
return {
|
||||
"users": {
|
||||
|
||||
+23
-8
@@ -89,8 +89,13 @@ async def get_qrcode_status(
|
||||
状态说明:
|
||||
- pending: 正在初始化
|
||||
- waiting_scan: 等待扫描(包含二维码图片 Base64)
|
||||
- success: 扫描成功(包含 user_id 和 authorization)
|
||||
- success: 扫描成功(包含 JWT token 和 user 信息)
|
||||
- error: 发生错误
|
||||
|
||||
认证架构说明:
|
||||
- 扫码成功后返回 JWT token(用于网站登录,21天有效期)
|
||||
- 同时更新数据库中的 authorization token(用于打卡业务)
|
||||
- 两种 token 分别管理,互不影响
|
||||
"""
|
||||
try:
|
||||
result = AuthService.get_qrcode_status(session_id, db)
|
||||
@@ -123,17 +128,22 @@ async def cancel_qrcode_session(
|
||||
)
|
||||
|
||||
|
||||
@router.post("/verify_token", response_model=dict, summary="验证 Token 有效性")
|
||||
@router.post("/verify_token", response_model=dict, summary="验证 JWT Token 有效性")
|
||||
async def verify_token(
|
||||
request: TokenVerifyRequest,
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""
|
||||
验证 Token 有效性
|
||||
验证 JWT Token 有效性(网站登录认证)
|
||||
|
||||
- **authorization**: Token(可带或不带 "Bearer " 前缀)
|
||||
- **authorization**: JWT Token(可带或不带 "Bearer " 前缀)
|
||||
|
||||
返回 Token 是否有效以及相关信息
|
||||
返回 Token 是否有效以及用户信息
|
||||
|
||||
注意:
|
||||
- 此接口验证的是 JWT token(用于网站登录,21天有效期)
|
||||
- 不验证打卡业务的 authorization token(存储在数据库中)
|
||||
- JWT token 过期需要重新登录,但打卡 token 过期不影响网站使用
|
||||
"""
|
||||
try:
|
||||
result = AuthService.verify_token(request.authorization, db)
|
||||
@@ -156,12 +166,17 @@ async def alias_login(
|
||||
- **alias**: 用户别名
|
||||
- **password**: 密码
|
||||
|
||||
返回登录结果,成功时包含 user_id 和 authorization
|
||||
返回登录结果,成功时包含 JWT token 和 user 信息
|
||||
|
||||
认证架构说明:
|
||||
- 登录成功后返回 JWT token(用于网站登录,21天有效期)
|
||||
- 如果数据库中的打卡 authorization token 过期,会返回警告信息
|
||||
- 打卡 token 过期不影响网站登录,但无法自动打卡,建议扫码更新
|
||||
|
||||
注意:
|
||||
- 用户必须已设置密码才能使用此方式登录
|
||||
- Token 必须仍然有效(未过期)
|
||||
- 如果 Token 已过期,请使用扫码登录重新获取
|
||||
- 即使打卡 token 已过期,仍然可以使用密码登录网站
|
||||
- 如需更新打卡 token,请使用扫码登录
|
||||
"""
|
||||
try:
|
||||
result = AuthService.alias_login(request.alias, request.password, db)
|
||||
|
||||
+11
-31
@@ -104,46 +104,26 @@ async def update_current_user_profile(
|
||||
)
|
||||
|
||||
|
||||
@router.get("/me/token_status", response_model=TokenStatus, summary="获取当前用户 Token 状态")
|
||||
@router.get("/me/token_status", response_model=TokenStatus, summary="获取当前用户打卡 Token 状态")
|
||||
async def get_current_user_token_status(
|
||||
current_user: User = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
获取当前用户的 Token 状态
|
||||
获取当前用户的打卡 Token 状态(authorization token,非 JWT)
|
||||
|
||||
注意:此接口检查的是打卡业务 token,不是网站登录 JWT token
|
||||
"""
|
||||
from datetime import datetime
|
||||
from backend.services.auth_service import AuthService
|
||||
|
||||
is_valid = True
|
||||
days_until_expiry = None
|
||||
expires_at = None
|
||||
expiring_soon = False
|
||||
|
||||
if current_user.jwt_exp and current_user.jwt_exp != "0":
|
||||
try:
|
||||
exp_timestamp = int(current_user.jwt_exp)
|
||||
current_timestamp = int(datetime.now().timestamp())
|
||||
expires_at = exp_timestamp
|
||||
|
||||
if current_timestamp > exp_timestamp:
|
||||
is_valid = False
|
||||
else:
|
||||
days_until_expiry = (exp_timestamp - current_timestamp) // 86400
|
||||
# 检查是否在30分钟内过期
|
||||
minutes_until_expiry = (exp_timestamp - current_timestamp) // 60
|
||||
expiring_soon = minutes_until_expiry <= 30
|
||||
|
||||
except ValueError as e:
|
||||
# jwt_exp 格式不正确,记录警告
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.warning(f"用户 {current_user.id} ({current_user.alias}) 的 jwt_exp 格式不正确: {current_user.jwt_exp}, 错误: {e}")
|
||||
# 使用统一的验证方法
|
||||
result = AuthService.verify_checkin_authorization(current_user)
|
||||
|
||||
return {
|
||||
"is_valid": is_valid,
|
||||
"is_valid": result["is_valid"],
|
||||
"jwt_exp": current_user.jwt_exp,
|
||||
"expires_at": expires_at,
|
||||
"days_until_expiry": days_until_expiry,
|
||||
"expiring_soon": expiring_soon
|
||||
"expires_at": result.get("expires_at"),
|
||||
"days_until_expiry": result.get("days_remaining"),
|
||||
"expiring_soon": result.get("expiring_soon", False)
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user