Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,19 @@ observability:

`APP_ENV` 未配置时默认 `prod`。`dev`/`development` 只用于本地开发;公网生产部署应保持 `APP_ENV=prod` 或 `APP_ENV=production` 并使用生产密钥。

## 邮箱注册 Turnstile

邮箱注册可选启用 Cloudflare Turnstile 人机验证,作用范围仅限邮箱注册;OAuth/OIDC 登录或注册不需要 Turnstile 校验。

相关运行时设置:

- `auth:turnstile_registration_enabled`:是否在邮箱注册时启用 Turnstile。
- `auth:turnstile_site_key`:前端渲染 Turnstile 组件使用的 Site Key,会通过 `/api/v1/auth/login-options` 返回。
- `auth:turnstile_secret_key`:后端调用 Cloudflare siteverify 使用的 Secret Key,属于敏感设置。
- `TURNSTILE_SITEVERIFY_URL` / `security.turnstile_siteverify_url`:可选覆盖 siteverify 端点,默认使用 Cloudflare 官方地址。

启用 Turnstile 需要同时启用 `auth:email_registration_enabled`,并配置 Site Key 与 Secret Key。开启邮箱验证码注册时,前端在 `/api/v1/auth/register/email/start` 提交 `turnstileToken`;关闭邮箱验证码但允许邮箱注册时,前端在 `/api/v1/auth/register/email/complete` 提交 `turnstileToken`。

生产环境安全校验:

- `APP_ENV` 支持 `dev`/`development` 和 `prod`/`production`,其他值会启动失败。
Expand Down
283 changes: 283 additions & 0 deletions backend/docs/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -3487,6 +3487,32 @@ const docTemplate = `{
}
}
},
"/auth/login-options": {
"get": {
"description": "获取用户名、邮箱、OAuth/OIDC 登录入口,以及邮箱注册 Turnstile 公共配置",
"produces": [
"application/json"
],
"tags": [
"auth"
],
"summary": "获取登录入口配置",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/internal_transport_http_auth.LoginOptionsResponseDoc"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/internal_transport_http_auth.ErrorDoc"
}
}
}
}
},
"/auth/logout": {
"post": {
"security": [
Expand Down Expand Up @@ -3605,6 +3631,86 @@ const docTemplate = `{
}
}
},
"/auth/register/email/complete": {
"post": {
"description": "使用邮箱、密码和验证码完成注册;未开启邮箱验证码但启用 Turnstile 时需要提交 turnstileToken",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"auth"
],
"summary": "完成邮箱注册",
"parameters": [
{
"description": "邮箱注册完成请求",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/internal_transport_http_auth.EmailRegistrationCompleteRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/internal_transport_http_auth.LoginResponseDoc"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/internal_transport_http_auth.ErrorDoc"
}
}
}
}
},
"/auth/register/email/start": {
"post": {
"description": "邮箱验证码注册开启时发送验证码;启用 Turnstile 后需要提交 turnstileToken",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"auth"
],
"summary": "发送邮箱注册验证码",
"parameters": [
{
"description": "邮箱注册验证码请求",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/internal_transport_http_auth.EmailRegistrationStartRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/internal_transport_http_auth.EmailRegistrationStartResponseDoc"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/internal_transport_http_auth.ErrorDoc"
}
}
}
}
},
"/auth/sessions": {
"get": {
"security": [
Expand Down Expand Up @@ -7683,6 +7789,69 @@ const docTemplate = `{
}
}
},
"internal_transport_http_auth.EmailRegistrationCompleteRequest": {
"type": "object",
"required": [
"email",
"password"
],
"properties": {
"code": {
"type": "string"
},
"email": {
"type": "string",
"maxLength": 128
},
"password": {
"type": "string",
"maxLength": 128,
"minLength": 8
},
"turnstileToken": {
"type": "string",
"maxLength": 2048
}
}
},
"internal_transport_http_auth.EmailRegistrationStartRequest": {
"type": "object",
"required": [
"email"
],
"properties": {
"email": {
"type": "string",
"maxLength": 128
},
"turnstileToken": {
"type": "string",
"maxLength": 2048
}
}
},
"internal_transport_http_auth.EmailRegistrationStartResponse": {
"type": "object",
"properties": {
"expiresAt": {
"type": "string"
},
"sent": {
"type": "boolean"
}
}
},
"internal_transport_http_auth.EmailRegistrationStartResponseDoc": {
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/internal_transport_http_auth.EmailRegistrationStartResponse"
},
"errorMsg": {
"type": "string"
}
}
},
"internal_transport_http_auth.EmailVerificationStartResponse": {
"type": "object",
"properties": {
Expand Down Expand Up @@ -7730,6 +7899,120 @@ const docTemplate = `{
}
}
},
"internal_transport_http_auth.IdentityProviderResponse": {
"type": "object",
"properties": {
"authURL": {
"type": "string"
},
"avatarField": {
"type": "string"
},
"clientID": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"defaultRole": {
"type": "string"
},
"discoveryURL": {
"type": "string"
},
"emailField": {
"type": "string"
},
"emailVerifiedField": {
"type": "string"
},
"issuerURL": {
"type": "string"
},
"jwksURL": {
"type": "string"
},
"loginEnabled": {
"type": "boolean"
},
"logoURL": {
"type": "string"
},
"name": {
"type": "string"
},
"nameField": {
"type": "string"
},
"publicID": {
"type": "string"
},
"registrationEnabled": {
"type": "boolean"
},
"scopes": {
"type": "string"
},
"slug": {
"type": "string"
},
"subjectField": {
"type": "string"
},
"tokenURL": {
"type": "string"
},
"type": {
"type": "string"
},
"updatedAt": {
"type": "string"
},
"userinfoURL": {
"type": "string"
}
}
},
"internal_transport_http_auth.LoginOptionsResponse": {
"type": "object",
"properties": {
"emailEnabled": {
"type": "boolean"
},
"emailRegistrationEnabled": {
"type": "boolean"
},
"emailVerificationEnabled": {
"type": "boolean"
},
"providers": {
"type": "array",
"items": {
"$ref": "#/definitions/internal_transport_http_auth.IdentityProviderResponse"
}
},
"turnstileRegistrationEnabled": {
"type": "boolean"
},
"turnstileSiteKey": {
"type": "string"
},
"usernameEnabled": {
"type": "boolean"
}
}
},
"internal_transport_http_auth.LoginOptionsResponseDoc": {
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/internal_transport_http_auth.LoginOptionsResponse"
},
"errorMsg": {
"type": "string"
}
}
},
"internal_transport_http_auth.LoginRequest": {
"type": "object",
"required": [
Expand Down
Loading
Loading