248 lines
9.4 KiB
Python
248 lines
9.4 KiB
Python
import secrets
|
||
from datetime import datetime, timedelta
|
||
from uuid import uuid4
|
||
|
||
from fastapi import APIRouter, Depends
|
||
from fastapi.responses import JSONResponse
|
||
from sqlalchemy import select
|
||
from sqlalchemy.ext.asyncio import AsyncSession
|
||
|
||
from loveace.config.logger import LoggerMixin
|
||
from loveace.database.auth.register import InviteCode as InviteCodeDB
|
||
from loveace.database.auth.register import RegisterCoolDown
|
||
from loveace.database.auth.token import AuthMEToken
|
||
from loveace.database.auth.user import ACEUser
|
||
from loveace.database.creator import get_db_session
|
||
from loveace.router.dependencies.logger import no_user_logger_mixin
|
||
from loveace.router.endpoint.auth.model.register import (
|
||
InviteCodeRequest,
|
||
InviteCodeResponse,
|
||
InviteErrorToCode,
|
||
RegisterErrorToCode,
|
||
RegisterRequest,
|
||
RegisterResponse,
|
||
)
|
||
from loveace.router.schemas.uniresponse import UniResponseModel
|
||
from loveace.service.remote.aufe import AUFEService
|
||
from loveace.service.remote.aufe.depends import get_aufe_service
|
||
from loveace.utils.rsa import RSAUtils
|
||
|
||
register_router = APIRouter(prefix="/register")
|
||
|
||
|
||
temp_tokens = []
|
||
|
||
rsa_util = RSAUtils.get_or_create_rsa_utils()
|
||
|
||
|
||
@register_router.post(
|
||
"/invite",
|
||
response_model=UniResponseModel[InviteCodeResponse],
|
||
responses=InviteErrorToCode.gen_code_table(),
|
||
summary="邀请码验证",
|
||
)
|
||
async def register(
|
||
invite_code: InviteCodeRequest,
|
||
db: AsyncSession = Depends(get_db_session),
|
||
logger: LoggerMixin = Depends(no_user_logger_mixin),
|
||
) -> UniResponseModel[InviteCodeResponse] | JSONResponse:
|
||
"""
|
||
验证邀请码并返回临时 Token
|
||
|
||
✅ 功能特性:
|
||
- 验证邀请码的有效性
|
||
- 生成临时 Token 用于后续注册步骤
|
||
- 邀请码一次性使用
|
||
|
||
💡 使用场景:
|
||
- 用户注册流程的第一步
|
||
- 邀请制系统的验证
|
||
|
||
Args:
|
||
invite_code: 邀请码请求对象
|
||
db: 数据库会话
|
||
logger: 日志记录器
|
||
|
||
Returns:
|
||
InviteCodeResponse: 包含临时 Token
|
||
"""
|
||
try:
|
||
async with db as session:
|
||
logger.info(f"邀请码: {invite_code.invite_code}")
|
||
invite = select(InviteCodeDB).where(
|
||
InviteCodeDB.code == invite_code.invite_code
|
||
)
|
||
result = await session.execute(invite)
|
||
invite_data = result.scalars().first()
|
||
if invite_data is None:
|
||
logger.info(f"邀请码不存在: {invite_code.invite_code}")
|
||
return InviteErrorToCode().invalid_invite_code.to_json_response(
|
||
logger.trace_id
|
||
)
|
||
token = secrets.token_urlsafe(128)
|
||
temp_tokens.append(token)
|
||
return UniResponseModel[InviteCodeResponse](
|
||
success=True,
|
||
data=InviteCodeResponse(token=token),
|
||
message="邀请码验证成功",
|
||
error=None,
|
||
)
|
||
except Exception as e:
|
||
logger.error("邀请码验证失败:")
|
||
logger.exception(e)
|
||
return InviteErrorToCode().server_error.to_json_response(logger.trace_id)
|
||
|
||
|
||
@register_router.post(
|
||
"/next",
|
||
response_model=UniResponseModel[RegisterResponse],
|
||
responses=RegisterErrorToCode.gen_code_table(),
|
||
summary="用户注册",
|
||
)
|
||
async def register_user(
|
||
register_info: RegisterRequest,
|
||
db: AsyncSession = Depends(get_db_session),
|
||
logger: LoggerMixin = Depends(no_user_logger_mixin),
|
||
aufe_service: AUFEService = Depends(get_aufe_service),
|
||
) -> UniResponseModel[RegisterResponse] | JSONResponse:
|
||
"""
|
||
用户注册,验证身份并创建账户
|
||
|
||
✅ 功能特性:
|
||
- 通过 AUFE 服务验证 EC 密码和登录密码
|
||
- 验证身份信息的有效性
|
||
- 生成 Authme Token 用于登录
|
||
|
||
⚠️ 限制条件:
|
||
- EC 密码或登录密码错误会触发 5 分钟冷却时间
|
||
- 用户 ID 不能重复
|
||
- 必须提供有效的邀请 Token
|
||
|
||
💡 使用场景:
|
||
- 新用户注册
|
||
- 创建学号对应的账户
|
||
|
||
Args:
|
||
register_info: 包含用户 ID、EC 密码、登录密码和邀请 Token 的注册信息
|
||
db: 数据库会话
|
||
logger: 日志记录器
|
||
aufe_service: AUFE 远程认证服务
|
||
|
||
Returns:
|
||
RegisterResponse: 包含 Authme Token
|
||
"""
|
||
try:
|
||
async with db as session:
|
||
# COOLDOWN检查
|
||
query = select(RegisterCoolDown).where(
|
||
RegisterCoolDown.userid == register_info.userid
|
||
)
|
||
result = await session.execute(query)
|
||
cooldown = result.scalars().first()
|
||
if cooldown:
|
||
if cooldown.expire_date > datetime.now():
|
||
logger.info(f"用户ID注册冷却中: {register_info.userid}")
|
||
return RegisterErrorToCode().userid_exists.to_json_response(
|
||
logger.trace_id
|
||
)
|
||
else:
|
||
await session.delete(cooldown)
|
||
await session.commit()
|
||
if register_info.token not in temp_tokens:
|
||
logger.info(f"无效的注册Token: {register_info.token}")
|
||
return RegisterErrorToCode().invalid_token.to_json_response(
|
||
logger.trace_id
|
||
)
|
||
query = select(ACEUser).where(ACEUser.userid == register_info.userid)
|
||
result = await session.execute(query)
|
||
user = result.scalars().first()
|
||
if user is not None:
|
||
logger.info(f"用户ID已存在: {register_info.userid}")
|
||
return RegisterErrorToCode().userid_exists.to_json_response(
|
||
logger.trace_id
|
||
)
|
||
# 尝试使用AUFE服务验证EC密码
|
||
try:
|
||
ec_password = rsa_util.decrypt(register_info.ec_password)
|
||
password = rsa_util.decrypt(register_info.password)
|
||
except Exception as e:
|
||
logger.info(f"用户 {register_info.userid} 提供的密码解密失败: {e}")
|
||
return RegisterErrorToCode().decrypt_error.to_json_response(
|
||
logger.trace_id
|
||
)
|
||
conn = await aufe_service.get_or_create_connection(
|
||
userid=register_info.userid,
|
||
ec_password=ec_password,
|
||
password=password,
|
||
)
|
||
ec_login_status = await conn.ec_login()
|
||
if not ec_login_status.success:
|
||
cooldown_entry = RegisterCoolDown(
|
||
userid=register_info.userid,
|
||
expire_date=datetime.now() + timedelta(minutes=5),
|
||
)
|
||
session.add(cooldown_entry)
|
||
await session.commit()
|
||
if ec_login_status.fail_invalid_credentials:
|
||
logger.info(f"EC密码错误: {register_info.userid}")
|
||
return RegisterErrorToCode().ec_password_error.to_json_response(
|
||
logger.trace_id
|
||
)
|
||
else:
|
||
logger.error(f"AUFE服务异常: {ec_login_status}")
|
||
return RegisterErrorToCode().ec_server_error.to_json_response(
|
||
logger.trace_id
|
||
)
|
||
|
||
uaap_login_status = await conn.uaap_login()
|
||
if not uaap_login_status.success:
|
||
cooldown_entry = RegisterCoolDown(
|
||
userid=register_info.userid,
|
||
expire_date=datetime.now() + timedelta(minutes=5),
|
||
)
|
||
session.add(cooldown_entry)
|
||
await session.commit()
|
||
if uaap_login_status.fail_invalid_credentials:
|
||
logger.info(f"登录密码错误: {register_info.userid}")
|
||
return RegisterErrorToCode().uaap_password_error.to_json_response(
|
||
logger.trace_id
|
||
)
|
||
else:
|
||
logger.error(f"AUFE服务异常: {uaap_login_status}")
|
||
return RegisterErrorToCode().ec_server_error.to_json_response(
|
||
logger.trace_id
|
||
)
|
||
# 创建新用户
|
||
new_user = ACEUser(
|
||
userid=register_info.userid,
|
||
ec_password=register_info.ec_password,
|
||
password=register_info.password,
|
||
)
|
||
session.add(new_user)
|
||
await session.commit()
|
||
# 注册成功后删除临时Token
|
||
temp_tokens.remove(register_info.token)
|
||
# 生成Authme Token
|
||
authme_token = secrets.token_urlsafe(128)
|
||
new_token = AuthMEToken(
|
||
user_id=new_user.userid, token=authme_token, device_id=uuid4().hex
|
||
)
|
||
session.add(new_token)
|
||
await session.commit()
|
||
return UniResponseModel[RegisterResponse](
|
||
success=True,
|
||
data=RegisterResponse(token=authme_token),
|
||
message="注册成功",
|
||
error=None,
|
||
)
|
||
except ValueError as ve:
|
||
logger.error("用户注册失败: RSA解密错误")
|
||
logger.exception(ve)
|
||
return RegisterErrorToCode().server_error.to_json_response(
|
||
logger.trace_id, "RSA解密错误,请检查授权密文"
|
||
)
|
||
except Exception as e:
|
||
logger.error("用户注册失败:")
|
||
logger.exception(e)
|
||
return RegisterErrorToCode().server_error.to_json_response(logger.trace_id)
|