schema.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. import re
  2. from datetime import datetime
  3. from typing import Optional
  4. from pydantic import BaseModel, ConfigDict, Field, model_validator, field_validator
  5. from sqlalchemy.ext.asyncio import AsyncSession
  6. from app.api.v1.module_system.user.model import UserModel
  7. from app.utils.sms_util import SmsTemplateEnum
  8. class SmsCodeSchema(BaseModel):
  9. # 验证手机号格式
  10. mobile: str = Field(..., description="手机号")
  11. # 短信模版
  12. template_name: str = Field(..., description="短信模版")
  13. # # 验证码
  14. code: Optional[str] = Field(default=None, description="验证码")
  15. @field_validator("mobile", mode="before")
  16. @classmethod
  17. def validate_mobile(cls, v: str) -> str:
  18. # 移除常见地格式化字符
  19. cleaned = re.sub(r'[\s\-+()()]', '', str(v))
  20. # 中国大陆手机号验证
  21. china_pattern = r'^1[3-9]\d{9}$'
  22. # 带国际区号的手机号
  23. # china_with_country_code = r'^(?:\+?86)?1[3-9]\d{9}$'
  24. # if not re.match(china_with_country_code, cleaned):
  25. # raise ValueError("手机号格式错误")
  26. if not re.match(china_pattern, cleaned):
  27. raise ValueError("手机号格式错误")
  28. # 返回清洗后的纯数字
  29. return cleaned.lstrip('+86')
  30. class AuthSchema(BaseModel):
  31. """权限认证模型"""
  32. model_config = ConfigDict(arbitrary_types_allowed=True)
  33. user: UserModel | None = Field(default=None, description="用户信息")
  34. check_data_scope: bool = Field(default=True, description="是否检查数据权限")
  35. db: AsyncSession = Field(description="数据库会话")
  36. tenant_id: int = Field(default=-1, description="租户ID")
  37. class JWTPayloadSchema(BaseModel):
  38. """JWT载荷模型"""
  39. sub: str = Field(..., description="用户登录信息")
  40. is_refresh: bool = Field(default=False, description="是否刷新token")
  41. exp: datetime | int = Field(..., description="过期时间")
  42. @model_validator(mode="after")
  43. def validate_fields(self):
  44. """
  45. 校验 JWT 载荷字段的基本合法性。
  46. 返回:
  47. - JWTPayloadSchema: 校验后的载荷实例。
  48. 异常:
  49. - ValueError: 必填字段为空或格式不正确时抛出。
  50. """
  51. if not self.sub or len(self.sub.strip()) == 0:
  52. raise ValueError("会话编号不能为空")
  53. return self
  54. class JWTOutSchema(BaseModel):
  55. """JWT响应模型"""
  56. model_config = ConfigDict(from_attributes=True)
  57. access_token: str = Field(..., min_length=1, description="访问token")
  58. refresh_token: str = Field(..., min_length=1, description="刷新token")
  59. token_type: str = Field(default="Bearer", description="token类型")
  60. expires_in: int = Field(..., gt=0, description="过期时间(秒)")
  61. class RefreshTokenPayloadSchema(BaseModel):
  62. """刷新Token载荷模型"""
  63. refresh_token: str = Field(..., min_length=1, description="刷新token")
  64. class LogoutPayloadSchema(BaseModel):
  65. """退出登录载荷模型"""
  66. token: str = Field(..., min_length=1, description="token")
  67. class CaptchaOutSchema(BaseModel):
  68. """验证码响应模型"""
  69. model_config = ConfigDict(from_attributes=True)
  70. enable: bool = Field(default=True, description="是否启用验证码")
  71. key: str = Field(..., min_length=1, description="验证码唯一标识")
  72. img_base: str = Field(..., min_length=1, description="Base64编码的验证码图片")
  73. class AutoLoginUserSchema(BaseModel):
  74. """免登录用户信息模型"""
  75. model_config = ConfigDict(from_attributes=True)
  76. id: int = Field(..., description="用户ID")
  77. username: str = Field(..., description="用户名")
  78. name: str = Field(..., description="用户姓名")
  79. avatar: str | None = Field(default=None, description="头像")
  80. class AutoLoginTokenSchema(BaseModel):
  81. """免登录Token响应模型"""
  82. model_config = ConfigDict(from_attributes=True)
  83. token: str = Field(..., description="免登录Token")
  84. user: AutoLoginUserSchema = Field(..., description="用户信息")
  85. class LoginMiniRequestSchema(BaseModel):
  86. """小程序登录请求模型"""
  87. model_config = ConfigDict(from_attributes=True)
  88. username: str = Field(..., min_length=1, description="用户名")
  89. password: str = Field(..., min_length=1, description="密码")
  90. login_type: Optional[str] = Field(default="mini", description="登录类型")
  91. class SmsLoginRequestSchema(SmsCodeSchema):
  92. code: str = Field(..., description="验证码")