""" 客户端认证接口 """ from fastapi import APIRouter, Depends, HTTPException, Request from sqlalchemy.orm import Session from pydantic import BaseModel from app.database import get_db from app.models.user import User from app.models.card import Card from app.models.recharge_record import RechargeRecord from app.core.security import verify_password, get_password_hash from app.core.encrypt import encryptor from app.core.logger import logger from app.config import settings from datetime import datetime, timedelta router = APIRouter() class RegisterRequest(BaseModel): """注册请求""" username: str password: str email: str card_code: str machine_code: str class LoginRequest(BaseModel): """登录请求""" username: str password: str machine_code: str class UnbindRequest(BaseModel): """解绑请求""" username: str password: str class ActivateCardRequest(BaseModel): """激活卡密请求""" user_id: int card_code: str @router.post("/register") async def register( request: Request, db: Session = Depends(get_db) ): """用户注册""" try: # 获取请求数据 data = await request.json() # 解密请求数据 if settings.ENCRYPT_ENABLED: encrypted_data = data.get("encrypted", "") if not encrypted_data: return {"code": 400, "msg": "缺少加密数据"} decrypted = encryptor.decrypt(encrypted_data) else: decrypted = data req = RegisterRequest(**decrypted) # 检查用户名是否存在 existing_user = db.query(User).filter(User.username == req.username).first() if existing_user: return {"code": 400, "msg": "用户名已存在"} # 验证卡密 card = db.query(Card).filter( Card.card_code == req.card_code, Card.status == 0 ).first() if not card: return {"code": 400, "msg": "卡密无效或已被使用"} # 计算到期时间 expire_time = datetime.now() + timedelta(days=card.days) # 创建用户 user = User( username=req.username, password=get_password_hash(req.password), email=req.email, machine_code=req.machine_code, card_id=card.id, expire_time=expire_time, status=1, created_at=datetime.now(), updated_at=datetime.now() ) db.add(user) db.flush() # 刷新以获取user.id # 更新卡密状态 card.user_id = user.id card.activated_at = datetime.now() card.expire_time = expire_time card.status = 1 card.updated_at = datetime.now() # 创建充值记录 recharge_record = RechargeRecord( user_id=user.id, card_id=card.id, software_code=card.software_code, days=card.days, expire_time_before=None, # 新用户,之前没有到期时间 expire_time_after=expire_time, created_at=datetime.now() ) db.add(recharge_record) db.commit() logger.info(f"用户注册成功: {req.username}") return {"code": 200, "msg": "注册成功", "data": {"user_id": user.id}} except Exception as e: db.rollback() logger.error(f"用户注册失败: {e}") return {"code": 500, "msg": "注册失败"} @router.post("/login") async def login( request: Request, db: Session = Depends(get_db) ): """用户登录""" try: # 获取请求数据 data = await request.json() # 解密请求数据 if settings.ENCRYPT_ENABLED: encrypted_data = data.get("encrypted", "") if not encrypted_data: return {"code": 400, "msg": "缺少加密数据"} decrypted = encryptor.decrypt(encrypted_data) else: decrypted = data req = LoginRequest(**decrypted) # 查找用户 user = db.query(User).filter(User.username == req.username).first() if not user: return {"code": 401, "msg": "用户名或密码错误"} # 验证密码 if not verify_password(req.password, user.password): return {"code": 401, "msg": "用户名或密码错误"} # 验证/绑定机器码 if user.machine_code: if user.machine_code != req.machine_code: return {"code": 403, "msg": "机器码不匹配,请先解绑"} else: # 用户已解绑或尚未绑定机器码,第一次登录时绑定当前机器码 user.machine_code = req.machine_code # 检查是否过期 if user.expire_time and user.expire_time < datetime.now(): return {"code": 403, "msg": "卡密已过期"} # 更新登录信息 client_ip = request.client.host if request.client else None user.last_login_time = datetime.now() user.last_login_ip = client_ip user.updated_at = datetime.now() db.commit() logger.info(f"用户登录成功: {req.username}") return { "code": 200, "msg": "登录成功", "data": { "user_id": user.id, "username": user.username, "expire_time": user.expire_time.isoformat() if user.expire_time else None } } except Exception as e: logger.error(f"用户登录失败: {e}") return {"code": 500, "msg": "登录失败"} @router.post("/unbind") async def unbind( request: Request, db: Session = Depends(get_db) ): """机器解绑""" try: # 获取请求数据 data = await request.json() # 解密请求数据 if settings.ENCRYPT_ENABLED: encrypted_data = data.get("encrypted", "") if not encrypted_data: return {"code": 400, "msg": "缺少加密数据"} decrypted = encryptor.decrypt(encrypted_data) else: decrypted = data req = UnbindRequest(**decrypted) # 查找用户 user = db.query(User).filter(User.username == req.username).first() if not user: return {"code": 401, "msg": "用户名或密码错误"} # 验证密码 if not verify_password(req.password, user.password): return {"code": 401, "msg": "用户名或密码错误"} # 解绑机器码 user.machine_code = None user.updated_at = datetime.now() db.commit() logger.info(f"机器解绑成功: {req.username}") return {"code": 200, "msg": "解绑成功"} except Exception as e: db.rollback() logger.error(f"机器解绑失败: {e}") return {"code": 500, "msg": "解绑失败"} @router.post("/heartbeat") async def heartbeat( request: Request, db: Session = Depends(get_db) ): """心跳检测""" try: # 获取请求数据 data = await request.json() # 解密请求数据 if settings.ENCRYPT_ENABLED: encrypted_data = data.get("encrypted", "") if not encrypted_data: return {"code": 400, "msg": "缺少加密数据"} decrypted = encryptor.decrypt(encrypted_data) else: decrypted = data user_id = decrypted.get("user_id") if not user_id: return {"code": 400, "msg": "参数错误"} # 查找用户 user = db.query(User).filter(User.id == user_id).first() if not user: return {"code": 404, "msg": "用户不存在"} # 检查是否过期 if user.expire_time and user.expire_time < datetime.now(): return {"code": 403, "msg": "卡密已过期"} return { "code": 200, "msg": "正常", "data": { "expire_time": user.expire_time.isoformat() if user.expire_time else None } } except Exception as e: logger.error(f"心跳检测失败: {e}") return {"code": 500, "msg": "心跳检测失败"} @router.post("/activate-card") async def activate_card( request: Request, db: Session = Depends(get_db) ): """激活卡密(充值)""" try: # 获取请求数据 data = await request.json() # 解密请求数据 if settings.ENCRYPT_ENABLED: encrypted_data = data.get("encrypted", "") if not encrypted_data: return {"code": 400, "msg": "缺少加密数据"} decrypted = encryptor.decrypt(encrypted_data) else: decrypted = data req = ActivateCardRequest(**decrypted) # 查找用户 user = db.query(User).filter(User.id == req.user_id).first() if not user: return {"code": 404, "msg": "用户不存在"} # 验证卡密 card = db.query(Card).filter( Card.card_code == req.card_code, Card.status == 0 ).first() if not card: return {"code": 400, "msg": "卡密无效或已被使用"} # 检查软件特征码是否匹配 software_code = decrypted.get("software_code", "") if card.software_code != software_code: return {"code": 400, "msg": "卡密与当前软件不匹配"} # 计算新的到期时间 expire_time_before = user.expire_time if expire_time_before and expire_time_before > datetime.now(): # 如果还有有效期,则累加 expire_time_after = expire_time_before + timedelta(days=card.days) else: # 如果已过期或没有有效期,则从当前时间开始计算 expire_time_after = datetime.now() + timedelta(days=card.days) # 更新用户到期时间 user.expire_time = expire_time_after user.updated_at = datetime.now() # 更新卡密状态 card.user_id = user.id card.activated_at = datetime.now() card.expire_time = expire_time_after card.status = 1 card.updated_at = datetime.now() # 创建充值记录 recharge_record = RechargeRecord( user_id=user.id, card_id=card.id, software_code=card.software_code, days=card.days, expire_time_before=expire_time_before, expire_time_after=expire_time_after, created_at=datetime.now() ) db.add(recharge_record) db.commit() logger.info(f"用户 {user.username} 激活卡密成功: {req.card_code}") return { "code": 200, "msg": "激活成功", "data": { "expire_time": expire_time_after.isoformat(), "days": card.days } } except Exception as e: db.rollback() logger.error(f"激活卡密失败: {e}") return {"code": 500, "msg": "激活失败"} @router.get("/recharge-records") async def get_recharge_records( request: Request, db: Session = Depends(get_db) ): """获取充值记录""" try: # 获取请求参数 params = dict(request.query_params) # 解密请求数据(如果有) user_id = None if settings.ENCRYPT_ENABLED: # GET请求可能通过query参数传递加密数据 encrypted_data = params.get("encrypted", "") if encrypted_data: decrypted = encryptor.decrypt(encrypted_data) user_id = decrypted.get("user_id") else: user_id = params.get("user_id") if user_id: user_id = int(user_id) if not user_id: return {"code": 400, "msg": "缺少用户ID"} # 查询充值记录 records = db.query(RechargeRecord).filter( RechargeRecord.user_id == user_id ).order_by(RechargeRecord.created_at.desc()).all() # 格式化返回数据 records_data = [] for record in records: # 获取卡密代码 card_code = "" if record.card_id: card = db.query(Card).filter(Card.id == record.card_id).first() if card: card_code = card.card_code records_data.append({ "id": record.id, "card_code": card_code, "days": record.days, "expire_time_before": record.expire_time_before.isoformat() if record.expire_time_before else None, "expire_time_after": record.expire_time_after.isoformat() if record.expire_time_after else None, "created_at": record.created_at.isoformat() if record.created_at else None }) return { "code": 200, "msg": "成功", "data": records_data } except Exception as e: logger.error(f"获取充值记录失败: {e}") return {"code": 500, "msg": "获取充值记录失败"}