113 lines
3.3 KiB
JSON
113 lines
3.3 KiB
JSON
{
|
|
"version": 1,
|
|
"path": "/api/auth/password",
|
|
"method": "POST",
|
|
"localSessionTtlSeconds": 86400,
|
|
"inputCases": [
|
|
{
|
|
"name": "phone and password are trimmed and user authMode input is ignored",
|
|
"body": {
|
|
"phone": " 13800138000 ",
|
|
"password": " TestPass123 ",
|
|
"authMode": "admin",
|
|
"next": " /assets "
|
|
},
|
|
"expectedRedirect": "/assets"
|
|
},
|
|
{
|
|
"name": "username is an accepted phone alias and unknown fields are ignored",
|
|
"body": {
|
|
"username": " 13800138000 ",
|
|
"password": "TestPass123",
|
|
"authMode": "something-else",
|
|
"ignored": true,
|
|
"next": "/create?mode=image#prompt"
|
|
},
|
|
"expectedRedirect": "/create?mode=image#prompt"
|
|
}
|
|
],
|
|
"safeNextCases": [
|
|
{ "input": null, "expected": "/create" },
|
|
{ "input": "", "expected": "/create" },
|
|
{ "input": "assets", "expected": "/create" },
|
|
{ "input": "//evil.example/path", "expected": "/create" },
|
|
{ "input": "https://evil.example/path", "expected": "/create" },
|
|
{ "input": "/\\evil.example/path", "expected": "/create" },
|
|
{ "input": "/api/auth/logout", "expected": "/create" },
|
|
{ "input": "/foo/../api/auth/logout", "expected": "/create" },
|
|
{ "input": "/foo/%2e%2e/api/auth/logout", "expected": "/create" },
|
|
{ "input": "/auth/login?next=/assets", "expected": "/create" },
|
|
{ "input": "/auth/admin-login", "expected": "/create" },
|
|
{ "input": "/assets/../usage?tab=mine#x", "expected": "/usage?tab=mine#x" },
|
|
{ "input": "/assets/.", "expected": "/assets/" },
|
|
{ "input": "/assets/%41", "expected": "/assets/%41" },
|
|
{ "input": "/assets/%2F/item", "expected": "/assets/%2F/item" },
|
|
{ "input": "/assets?tab=mine#recent", "expected": "/assets?tab=mine#recent" }
|
|
],
|
|
"success": {
|
|
"topLevelKeys": ["ok", "redirectTo", "user", "authMode"],
|
|
"publicUserKeys": [
|
|
"id",
|
|
"subject",
|
|
"username",
|
|
"phone",
|
|
"displayName",
|
|
"clientId",
|
|
"organizationId",
|
|
"organizationName",
|
|
"role",
|
|
"status",
|
|
"authorities",
|
|
"scope"
|
|
],
|
|
"forbiddenSerializedKeys": [
|
|
"password",
|
|
"passwordHash",
|
|
"passwordSalt",
|
|
"failedLoginCount",
|
|
"lockedUntil",
|
|
"lastLoginAt",
|
|
"sessionVersion",
|
|
"issuedAt",
|
|
"expiresAt",
|
|
"accessToken",
|
|
"tokenType"
|
|
]
|
|
},
|
|
"errors": {
|
|
"invalidInput": {
|
|
"status": 400,
|
|
"body": { "error": "手机号和密码不能为空。" }
|
|
},
|
|
"invalidCredentials": {
|
|
"status": 401,
|
|
"body": { "error": "手机号或密码错误。" }
|
|
},
|
|
"disabledAccount": {
|
|
"status": 403,
|
|
"body": { "error": "账号已停用,请联系管理员。" }
|
|
},
|
|
"disabledOrganization": {
|
|
"status": 403,
|
|
"body": { "error": "所属组织已停用,请联系管理员。" }
|
|
},
|
|
"lockedAccount": {
|
|
"status": 423,
|
|
"body": { "error": "登录失败次数过多,请 15 分钟后再试。" }
|
|
},
|
|
"rateLimited": {
|
|
"status": 429,
|
|
"body": { "error": "请求过于频繁,请稍后再试。" }
|
|
},
|
|
"unconfigured": {
|
|
"status": 503,
|
|
"body": { "error": "账号认证配置不完整:ZHINIAN_AUTH_SESSION_SECRET" }
|
|
}
|
|
},
|
|
"rateLimit": {
|
|
"attemptsPerIp": 30,
|
|
"windowSeconds": 900
|
|
},
|
|
"cookieFixture": "session-cookie-v1.json"
|
|
}
|