keys.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. """
  2. 密钥管理接口
  3. """
  4. from fastapi import APIRouter, Depends, Request
  5. from sqlalchemy.orm import Session
  6. from fastapi import Body
  7. from app.database import get_db
  8. from app.api.deps import get_current_admin
  9. from app.models.api_key import APIKey
  10. from app.models.key_rotation_config import KeyRotationConfig
  11. from app.core.encrypt import encryptor
  12. from datetime import datetime, timedelta
  13. from app.utils.timezone import beijing_now
  14. from app.config import settings
  15. router = APIRouter()
  16. @router.get("/current")
  17. async def get_current_key(
  18. db: Session = Depends(get_db),
  19. current_admin = Depends(get_current_admin)
  20. ):
  21. """获取当前密钥"""
  22. key = db.query(APIKey).filter(APIKey.is_active == 1).order_by(APIKey.key_version.desc()).first()
  23. if not key:
  24. return {"code": 404, "msg": "未找到激活的密钥"}
  25. return {
  26. "code": 200,
  27. "msg": "成功",
  28. "data": {
  29. "public_key": key.public_key,
  30. "private_key": key.private_key,
  31. "key_version": key.key_version,
  32. "expire_at": key.expire_at.isoformat() if key.expire_at else None
  33. }
  34. }
  35. @router.get("/history")
  36. async def get_key_history(
  37. db: Session = Depends(get_db),
  38. current_admin = Depends(get_current_admin)
  39. ):
  40. """获取历史密钥"""
  41. keys = db.query(APIKey).order_by(APIKey.key_version.desc()).all()
  42. return {
  43. "code": 200,
  44. "msg": "成功",
  45. "data": [
  46. {
  47. "id": k.id,
  48. "key_version": k.key_version,
  49. "is_active": bool(k.is_active),
  50. "public_key": k.public_key,
  51. "private_key": k.private_key,
  52. "created_at": k.created_at.isoformat() if k.created_at else None,
  53. "expire_at": k.expire_at.isoformat() if k.expire_at else None
  54. }
  55. for k in keys
  56. ]
  57. }
  58. @router.post("/rotate")
  59. async def rotate_key(
  60. request: Request,
  61. db: Session = Depends(get_db),
  62. current_admin = Depends(get_current_admin)
  63. ):
  64. """立即更新密钥"""
  65. # 获取当前激活的密钥
  66. current_key = db.query(APIKey).filter(APIKey.is_active == 1).order_by(APIKey.key_version.desc()).first()
  67. # 生成新密钥
  68. new_key_pair = encryptor.generate_key_pair()
  69. new_version = (current_key.key_version + 1) if current_key else 1
  70. # 获取配置,确定过期时间
  71. config = db.query(KeyRotationConfig).first()
  72. rotation_days = config.rotation_days if config else settings.KEY_ROTATION_DAYS
  73. expire_at = beijing_now() + timedelta(days=rotation_days)
  74. # 禁用旧密钥
  75. if current_key:
  76. current_key.is_active = 0
  77. current_key.updated_at = beijing_now()
  78. # 创建新密钥
  79. new_key = APIKey(
  80. public_key=new_key_pair[1], # 公钥 (public_pem)
  81. private_key=new_key_pair[0], # 私钥 (private_pem)
  82. key_version=new_version,
  83. is_active=1,
  84. expire_at=expire_at,
  85. created_at=beijing_now(),
  86. updated_at=beijing_now()
  87. )
  88. db.add(new_key)
  89. # 刷新以获取ID
  90. db.flush()
  91. # 创建历史记录
  92. from app.utils.history import create_api_key_history, create_operation_log
  93. if current_key:
  94. create_api_key_history(db, current_key, "UPDATE")
  95. create_api_key_history(db, new_key, "INSERT")
  96. # 记录操作日志
  97. client_ip = request.client.host if request.client else None
  98. old_version = current_key.key_version if current_key else None
  99. create_operation_log(
  100. db=db,
  101. admin_id=current_admin.id,
  102. module="密钥管理",
  103. action="密钥轮换",
  104. description=f"执行密钥轮换:版本 {old_version} -> {new_version}",
  105. old_data={"old_version": old_version},
  106. new_data={"new_version": new_version, "rotation_days": rotation_days},
  107. ip_address=client_ip
  108. )
  109. # 一次性提交所有更改
  110. db.commit()
  111. return {
  112. "code": 200,
  113. "msg": "密钥更新成功",
  114. "data": {
  115. "public_key": new_key.public_key,
  116. "private_key": new_key.private_key,
  117. "key_version": new_key.key_version,
  118. "expire_at": new_key.expire_at.isoformat() if new_key.expire_at else None
  119. }
  120. }
  121. @router.put("/cycle")
  122. async def update_key_cycle(
  123. req: dict = Body(...),
  124. request: Request = None,
  125. db: Session = Depends(get_db),
  126. current_admin = Depends(get_current_admin)
  127. ):
  128. """更新密钥轮换周期"""
  129. rotation_days = req.get("rotation_days")
  130. if not rotation_days or rotation_days < 1:
  131. return {"code": 400, "msg": "轮换周期必须大于0"}
  132. # 获取或创建配置
  133. config = db.query(KeyRotationConfig).first()
  134. old_rotation_days = config.rotation_days if config else None
  135. if not config:
  136. config = KeyRotationConfig(
  137. rotation_days=rotation_days,
  138. is_auto_rotate=1,
  139. updated_at=beijing_now()
  140. )
  141. db.add(config)
  142. else:
  143. config.rotation_days = rotation_days
  144. config.updated_at = beijing_now()
  145. # 创建历史记录
  146. from app.utils.history import create_key_rotation_config_history, create_operation_log
  147. create_key_rotation_config_history(db, config, "INSERT" if not old_rotation_days else "UPDATE")
  148. # 记录操作日志
  149. client_ip = request.client.host if request and request.client else None
  150. create_operation_log(
  151. db=db,
  152. admin_id=current_admin.id,
  153. module="密钥管理",
  154. action="更新轮换周期",
  155. description=f"更新密钥轮换周期:{old_rotation_days}天 -> {rotation_days}天",
  156. old_data={"rotation_days": old_rotation_days},
  157. new_data={"rotation_days": rotation_days},
  158. ip_address=client_ip
  159. )
  160. # 一次性提交所有更改
  161. db.commit()
  162. return {"code": 200, "msg": "更新成功"}