优化验证

This commit is contained in:
咕谷酱
2025-09-24 02:08:13 +08:00
parent 8054281b15
commit 86c7bbb74e
13 changed files with 891 additions and 5 deletions

View File

@@ -7,7 +7,6 @@ from app.auth import (
totp_redis_key,
verify_totp_key_with_replay_protection,
)
from app.config import settings
from app.const import BACKUP_CODE_LENGTH
from app.database.auth import TotpKeys
from app.database.lazer_user import User
@@ -19,9 +18,38 @@ from .router import router
from fastapi import Body, Depends, HTTPException, Security
import pyotp
from pydantic import BaseModel
from redis.asyncio import Redis
class TotpStatusResp(BaseModel):
"""TOTP状态响应"""
enabled: bool
created_at: str | None = None
@router.get(
"/totp/status",
name="检查 TOTP 状态",
description="检查当前用户是否已启用 TOTP 双因素验证",
tags=["验证", "g0v0 API"],
response_model=TotpStatusResp,
)
async def get_totp_status(
current_user: User = Security(get_client_user),
):
"""检查用户是否已创建TOTP"""
totp_key = await current_user.awaitable_attrs.totp_key
if totp_key:
return TotpStatusResp(
enabled=True,
created_at=totp_key.created_at.isoformat()
)
else:
return TotpStatusResp(enabled=False)
@router.post(
"/totp/create",
name="开始 TOTP 创建流程",
@@ -44,11 +72,16 @@ async def start_create_totp(
previous = await redis.hgetall(totp_redis_key(current_user)) # pyright: ignore[reportGeneralTypeIssues]
if previous: # pyright: ignore[reportGeneralTypeIssues]
from app.auth import _generate_totp_account_label, _generate_totp_issuer_name
account_label = _generate_totp_account_label(current_user)
issuer_name = _generate_totp_issuer_name()
return StartCreateTotpKeyResp(
secret=previous["secret"],
uri=pyotp.totp.TOTP(previous["secret"]).provisioning_uri(
name=current_user.email,
issuer_name=settings.totp_issuer,
name=account_label,
issuer_name=issuer_name,
),
)
return await start_create_totp_key(current_user, redis)

View File

@@ -86,6 +86,7 @@ async def verify_session(
if verify_method is None:
# 智能选择验证方法参考osu-web实现
# API版本较老或用户未设置TOTP时强制使用邮件验证
print(api_version, totp_key)
if api_version < 20240101 or totp_key is None:
verify_method = "mail"
else: