user_service.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. """
  2. 用户服务层
  3. 提供用户CRUD操作和管理员初始化功能
  4. 需求: 3.1, 3.2, 3.3, 7.1, 7.2, 7.3, 7.4, 9.1, 10.1, 10.2
  5. """
  6. import os
  7. import uuid
  8. from datetime import date
  9. from typing import Optional
  10. from fastapi import HTTPException
  11. from sqlalchemy.orm import Session
  12. from app.models.user import User
  13. from app.schemas.user_schema import UserCreate, UserUpdate, UserResponse
  14. from app.services.auth_service import AuthService
  15. from app.services.password_security_service import PasswordSecurityService
  16. class UserService:
  17. """用户业务服务类"""
  18. def __init__(self, db: Session):
  19. self.db = db
  20. def create_user(self, data: UserCreate) -> User:
  21. """创建新用户"""
  22. # 检查用户名是否已存在
  23. if self.db.query(User).filter(User.username == data.username).first():
  24. raise HTTPException(status_code=409, detail="Username already exists")
  25. # 检查邮箱是否已存在
  26. if data.email:
  27. if self.db.query(User).filter(User.email == data.email).first():
  28. raise HTTPException(status_code=409, detail="Email already exists")
  29. # 检查手机号是否已被注册
  30. if data.phone:
  31. if self.db.query(User).filter(User.phone == data.phone).first():
  32. raise HTTPException(status_code=409, detail="该手机号已被注册")
  33. # 检查密码强度
  34. if PasswordSecurityService.is_password_weak(data.password):
  35. raise HTTPException(
  36. status_code=400,
  37. detail="密码过于简单,请设置更复杂的密码"
  38. )
  39. # 验证密码基本要求
  40. is_valid, errors = PasswordSecurityService.validate_password_requirements(data.password)
  41. if not is_valid:
  42. error_msg = "密码不符合要求:" + ";".join(errors)
  43. raise HTTPException(status_code=400, detail=error_msg)
  44. # 优先从 local_config db 读取 admin_api_key,没有则回退到环境变量
  45. try:
  46. from app.services import local_config_service as _lcs
  47. default_apikey = _lcs.get_admin_api_key() or os.getenv("ADMIN_API_KEY")
  48. except Exception:
  49. default_apikey = os.getenv("ADMIN_API_KEY")
  50. user = User(
  51. id=str(uuid.uuid4()),
  52. username=data.username,
  53. password_hash=AuthService.hash_password(data.password),
  54. nickname=data.nickname,
  55. email=data.email,
  56. phone=data.phone if data.phone else None,
  57. apikey=default_apikey,
  58. registration_date=date.today()
  59. )
  60. self.db.add(user)
  61. self.db.commit()
  62. self.db.refresh(user)
  63. return user
  64. def get_user_by_id(self, user_id: str) -> Optional[User]:
  65. """根据ID获取用户"""
  66. return self.db.query(User).filter(User.id == user_id).first()
  67. def get_user_by_username(self, username: str) -> Optional[User]:
  68. """根据用户名获取用户"""
  69. return self.db.query(User).filter(User.username == username).first()
  70. def update_user(self, user_id: str, data: UserUpdate) -> User:
  71. """更新用户信息"""
  72. user = self.get_user_by_id(user_id)
  73. if not user:
  74. raise HTTPException(status_code=404, detail="User not found")
  75. # 检查邮箱唯一性
  76. if data.email:
  77. existing = self.db.query(User).filter(
  78. User.email == data.email, User.id != user_id
  79. ).first()
  80. if existing:
  81. raise HTTPException(status_code=409, detail="Email already exists")
  82. # 检查手机号唯一性
  83. if data.phone:
  84. existing = self.db.query(User).filter(
  85. User.phone == data.phone, User.id != user_id
  86. ).first()
  87. if existing:
  88. raise HTTPException(status_code=409, detail="该手机号已被其他账号绑定")
  89. # 只更新提供的字段
  90. update_data = data.model_dump(exclude_unset=True)
  91. for field, value in update_data.items():
  92. setattr(user, field, value)
  93. self.db.commit()
  94. self.db.refresh(user)
  95. return user
  96. def submit_verification(self, user_id: str, encrypted_data: str) -> User:
  97. """
  98. 提交实名认证
  99. Args:
  100. user_id: 用户ID
  101. encrypted_data: RSA加密的数据(格式: real_name|id_card)
  102. """
  103. from app.services.encryption_service import encryption_service
  104. from app.services.id_card_validator import IDCardValidator, validate_real_name
  105. user = self.get_user_by_id(user_id)
  106. if not user:
  107. raise HTTPException(status_code=404, detail="User not found")
  108. # 检查是否已经认证通过
  109. if user.is_verified == "verified":
  110. raise HTTPException(status_code=400, detail="用户已完成实名认证")
  111. # RSA解密数据
  112. try:
  113. decrypted_data = encryption_service.rsa_decrypt(encrypted_data)
  114. parts = decrypted_data.split('|')
  115. if len(parts) != 2:
  116. raise ValueError("数据格式错误")
  117. real_name, id_card = parts
  118. except Exception as e:
  119. raise HTTPException(status_code=400, detail=f"数据解密失败: {str(e)}")
  120. # 验证真实姓名
  121. valid, error = validate_real_name(real_name)
  122. if not valid:
  123. raise HTTPException(status_code=400, detail=error)
  124. # 验证身份证号
  125. valid, error = IDCardValidator.validate(id_card)
  126. if not valid:
  127. raise HTTPException(status_code=400, detail=error)
  128. # 统一转大写
  129. id_card = id_card.upper().strip()
  130. # AES加密身份证号用于存储
  131. encrypted_id_card = encryption_service.aes_encrypt(id_card)
  132. # 检查身份证号是否已被使用(需要解密所有已认证用户的身份证号进行比对)
  133. verified_users = self.db.query(User).filter(
  134. User.is_verified == "verified",
  135. User.id != user_id,
  136. User.id_card.isnot(None)
  137. ).all()
  138. for verified_user in verified_users:
  139. try:
  140. existing_id_card = encryption_service.aes_decrypt(verified_user.id_card)
  141. if existing_id_card == id_card:
  142. raise HTTPException(status_code=409, detail="该身份证号已被其他用户使用")
  143. except:
  144. # 如果解密失败,跳过(可能是旧数据)
  145. continue
  146. # 更新用户信息
  147. user.real_name = real_name
  148. user.id_card = encrypted_id_card # 存储加密后的身份证号
  149. user.is_verified = "verified"
  150. from datetime import datetime
  151. user.verified_at = datetime.now()
  152. self.db.commit()
  153. self.db.refresh(user)
  154. return user
  155. def delete_user(self, user_id: str) -> None:
  156. """删除用户(彻底从数据库移除)。"""
  157. user = self.get_user_by_id(user_id)
  158. if not user:
  159. raise HTTPException(status_code=404, detail="User not found")
  160. # 直接删除用户记录
  161. self.db.delete(user)
  162. self.db.commit()
  163. def init_admin_user(self) -> None:
  164. """初始化管理员用户"""
  165. admin = self.db.query(User).filter(User.username == "admin").first()
  166. if not admin:
  167. try:
  168. from app.services import local_config_service as _lcs
  169. admin_apikey = _lcs.get_admin_api_key() or os.getenv("ADMIN_API_KEY")
  170. except Exception:
  171. admin_apikey = os.getenv("ADMIN_API_KEY")
  172. admin = User(
  173. id=str(uuid.uuid4()),
  174. username="admin",
  175. password_hash=AuthService.hash_password("admin123"),
  176. nickname="管理员",
  177. email="wxcz@wxcz.com",
  178. apikey=admin_apikey,
  179. registration_date=date.today()
  180. )
  181. self.db.add(admin)
  182. self.db.commit()