simple_auth.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. from pydantic import BaseModel, Field, validator
  2. from typing import Optional, List
  3. class TicketExchangeRequest(BaseModel):
  4. app_id: str
  5. target_app_id: str
  6. user_mobile: str
  7. timestamp: int
  8. sign: str
  9. class TicketExchangeResponse(BaseModel):
  10. ticket: str
  11. redirect_url: str
  12. class TicketValidateRequest(BaseModel):
  13. ticket: str
  14. app_id: str # The app trying to validate
  15. sign: str
  16. timestamp: int
  17. class TicketValidateResponse(BaseModel):
  18. valid: bool
  19. user_id: Optional[int] = None
  20. mobile: Optional[str] = None
  21. mapped_key: Optional[str] = None
  22. mapped_email: Optional[str] = None
  23. class PasswordLoginRequest(BaseModel):
  24. app_id: Optional[str] = Field(
  25. None,
  26. description="应用ID。不提供时为平台登录(返回access_token),提供时为应用SSO登录(返回ticket)"
  27. )
  28. identifier: str = Field(
  29. ...,
  30. description="用户标识:手机号、映射key或映射email"
  31. )
  32. password: str = Field(
  33. ...,
  34. description="用户密码"
  35. )
  36. remember_me: bool = Field(
  37. False,
  38. description="是否记住登录(长期有效)"
  39. )
  40. sign: Optional[str] = Field(
  41. None,
  42. description="签名(可选)。如果提供,必须同时提供timestamp。用于服务端安全调用"
  43. )
  44. timestamp: Optional[int] = Field(
  45. None,
  46. description="时间戳(可选)。如果提供,必须同时提供sign"
  47. )
  48. @validator('timestamp')
  49. def validate_sign_timestamp(cls, v, values):
  50. """验证 sign 和 timestamp 必须同时提供或同时不提供"""
  51. sign = values.get('sign')
  52. if (sign and not v) or (not sign and v):
  53. raise ValueError('sign 和 timestamp 必须同时提供或同时不提供')
  54. return v
  55. class PasswordLoginResponse(BaseModel):
  56. ticket: Optional[str] = Field(
  57. None,
  58. description="票据。当提供app_id时返回,用于应用SSO登录"
  59. )
  60. access_token: Optional[str] = Field(
  61. None,
  62. description="访问令牌。当未提供app_id时返回,用于平台登录"
  63. )
  64. token_type: Optional[str] = Field(
  65. None,
  66. description="令牌类型,固定为 'bearer'"
  67. )
  68. role: Optional[str] = Field(
  69. None,
  70. description="用户角色:SUPER_ADMIN / DEVELOPER / ORDINARY_USER"
  71. )
  72. class UserRegisterRequest(BaseModel):
  73. mobile: str
  74. password: str
  75. name: str # Added field
  76. app_id: Optional[str] = None # Optional, if registering via an app context
  77. class AdminPasswordResetRequest(BaseModel):
  78. user_id: int
  79. admin_password: str
  80. class AdminPasswordResetResponse(BaseModel):
  81. new_password: str
  82. class ChangePasswordRequest(BaseModel):
  83. old_password: str
  84. new_password: str
  85. class UserMappingResponse(BaseModel):
  86. app_name: str
  87. app_id: str
  88. protocol_type: str
  89. mapped_key: Optional[str] = None
  90. mapped_email: Optional[str] = None
  91. is_active: bool
  92. class MyMappingsResponse(BaseModel):
  93. total: int
  94. items: List[UserMappingResponse]
  95. class UserPromoteRequest(BaseModel):
  96. user_id: int
  97. new_role: str
  98. class SsoLoginRequest(BaseModel):
  99. app_id: str = Field(
  100. ...,
  101. description="应用ID(必填)。只支持 SIMPLE_API 类型的应用"
  102. )
  103. username: Optional[str] = Field(
  104. None,
  105. description="用户名(条件必填)。如果用户未登录UAP平台,则必须提供 username 和 password"
  106. )
  107. password: Optional[str] = Field(
  108. None,
  109. description="密码(条件必填)。如果用户未登录UAP平台,则必须提供 username 和 password"
  110. )
  111. class Config:
  112. schema_extra = {
  113. "examples": [
  114. {
  115. "description": "场景1:用户已登录UAP(使用会话)",
  116. "value": {
  117. "app_id": "my_app_123"
  118. }
  119. },
  120. {
  121. "description": "场景2:用户未登录(使用凭据)",
  122. "value": {
  123. "app_id": "my_app_123",
  124. "username": "13800138000",
  125. "password": "password123"
  126. }
  127. }
  128. ]
  129. }
  130. class SsoLoginResponse(BaseModel):
  131. redirect_url: str = Field(
  132. ...,
  133. description="带票据的重定向URL,格式:{应用回调URL}?ticket={票据}。前端应直接跳转到此URL"
  134. )