100 lines
3.0 KiB
Python
100 lines
3.0 KiB
Python
from __future__ import annotations
|
||
|
||
from datetime import datetime
|
||
|
||
from pydantic import BaseModel, Field, field_validator
|
||
|
||
|
||
class SsoTicketRequest(BaseModel):
|
||
externalUserId: str = Field(min_length=1, max_length=120)
|
||
verifiedPhone: str | None = Field(default=None, min_length=11, max_length=20)
|
||
displayName: str | None = Field(default=None, max_length=100)
|
||
returnUrl: str | None = Field(default=None, max_length=1000)
|
||
|
||
|
||
class SsoExchangeRequest(BaseModel):
|
||
code: str = Field(min_length=20, max_length=200)
|
||
|
||
|
||
class SsoClientSaveRequest(BaseModel):
|
||
appId: str = Field(min_length=3, max_length=80, pattern=r"^[A-Za-z0-9][A-Za-z0-9._-]+$")
|
||
name: str = Field(min_length=1, max_length=100)
|
||
redirectUris: list[str] = Field(default_factory=list, max_length=20)
|
||
status: int = Field(default=1, ge=0, le=1)
|
||
|
||
@field_validator("redirectUris")
|
||
@classmethod
|
||
def validate_redirect_uris(cls, values: list[str]) -> list[str]:
|
||
cleaned: list[str] = []
|
||
for raw in values:
|
||
value = raw.strip()
|
||
if not value:
|
||
continue
|
||
if not value.startswith(("https://", "http://localhost", "http://127.0.0.1")):
|
||
raise ValueError("回跳地址必须使用 HTTPS;本地调试可使用 localhost 或 127.0.0.1")
|
||
if value not in cleaned:
|
||
cleaned.append(value)
|
||
return cleaned
|
||
|
||
|
||
class SsoClientUpdateRequest(BaseModel):
|
||
name: str = Field(min_length=1, max_length=100)
|
||
redirectUris: list[str] = Field(default_factory=list, max_length=20)
|
||
status: int = Field(default=1, ge=0, le=1)
|
||
|
||
@field_validator("redirectUris")
|
||
@classmethod
|
||
def validate_redirect_uris(cls, values: list[str]) -> list[str]:
|
||
return SsoClientSaveRequest.validate_redirect_uris(values)
|
||
|
||
|
||
class SsoPublicConfigRequest(BaseModel):
|
||
userClientUrl: str = Field(default="", max_length=1000)
|
||
|
||
@field_validator("userClientUrl")
|
||
@classmethod
|
||
def validate_user_client_url(cls, value: str) -> str:
|
||
cleaned = value.strip().rstrip("/")
|
||
if cleaned and not cleaned.startswith(("https://", "http://localhost", "http://127.0.0.1")):
|
||
raise ValueError("用户端公网地址必须使用 HTTPS;本地调试可使用 localhost 或 127.0.0.1")
|
||
return cleaned
|
||
|
||
|
||
class SsoClientItem(BaseModel):
|
||
id: int
|
||
appId: str
|
||
name: str
|
||
redirectUris: list[str]
|
||
status: int
|
||
identityCount: int
|
||
lastUsedAt: datetime | None = None
|
||
createdAt: datetime
|
||
updatedAt: datetime
|
||
|
||
|
||
class SsoIdentityItem(BaseModel):
|
||
id: int
|
||
clientId: int
|
||
clientName: str
|
||
appId: str
|
||
userId: int
|
||
userName: str
|
||
phone: str
|
||
externalUserId: str
|
||
displayNameSnapshot: str | None = None
|
||
lastLoginAt: datetime | None = None
|
||
createdAt: datetime
|
||
|
||
|
||
class SsoAuditItem(BaseModel):
|
||
id: int
|
||
appId: str | None = None
|
||
clientName: str | None = None
|
||
userId: int | None = None
|
||
externalUserId: str | None = None
|
||
action: str
|
||
status: str
|
||
errorMessage: str | None = None
|
||
ip: str | None = None
|
||
createdAt: datetime
|