| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424 |
- """
- 客户端认证接口
- """
- 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": "获取充值记录失败"}
|