Skip to content

认证 API ​

用户认证和授权相关的 API 端点。

端点概览 ​

方法端点描述认证
POST/auth/login用户登录❌
POST/auth/register用户注册❌
POST/auth/logout用户登出✅
POST/auth/github/authorize-url获取 GitHub OAuth URL❌
GET/auth/github/callbackGitHub OAuth 回调❌
POST/auth/password/forgot忘记密码❌
POST/auth/password/reset重置密码❌
GET/me获取当前用户信息✅
PATCH/me更新当前用户信息✅
POST/me/password修改密码✅

用户登录 ​

POST /api/v1/auth/login ​

使用邮箱/用户名和密码登录。

请求 ​

http
POST /api/v1/auth/login
Content-Type: application/json

{
  "identifier": "user@example.com",
  "password": "your_password",
  "turnstile_token": "optional_cloudflare_token"
}

参数说明:

字段类型必填说明
identifierstring✅邮箱或用户名
passwordstring✅密码(至少8位)
turnstile_tokenstring❌Cloudflare Turnstile 验证令牌

响应 ​

成功 (200 OK):

json
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expires_at": "2024-01-02T12:00:00Z",
  "user": {
    "user_id": "550e8400-e29b-41d4-a716-446655440000",
    "username": "johndoe",
    "email": "user@example.com",
    "role": "user",
    "status": "active",
    "last_login_at": "2024-01-01T12:00:00Z"
  }
}

错误响应:

  • 400 Bad Request: 参数格式错误
  • 401 Unauthorized: 用户名或密码错误
  • 403 Forbidden: 账户被暂停

示例 ​

typescript
const login = async (identifier: string, password: string) => {
  const response = await fetch('/api/v1/auth/login', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ identifier, password }),
  });
  
  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.error);
  }
  
  const data = await response.json();
  localStorage.setItem('token', data.token);
  return data;
};

用户注册 ​

POST /api/v1/auth/register ​

注册新用户账户。

请求 ​

http
POST /api/v1/auth/register
Content-Type: application/json

{
  "username": "johndoe",
  "email": "user@example.com",
  "password": "securepassword123",
  "turnstile_token": "optional_cloudflare_token"
}

参数说明:

字段类型必填说明
usernamestring✅用户名(3-30位,字母数字下划线)
emailstring✅邮箱地址
passwordstring✅密码(至少8位)
turnstile_tokenstring❌Cloudflare Turnstile 验证令牌

验证规则:

  • 用户名: 3-30 个字符,只能包含字母、数字、下划线和连字符
  • 邮箱: 有效的邮箱格式
  • 密码: 至少 8 个字符

响应 ​

成功 (201 Created):

json
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expires_at": "2024-01-02T12:00:00Z",
  "user": {
    "user_id": "550e8400-e29b-41d4-a716-446655440000",
    "username": "johndoe",
    "email": "user@example.com",
    "role": "user",
    "status": "active"
  }
}

错误响应:

  • 400 Bad Request: 参数验证失败
  • 409 Conflict: 用户名或邮箱已存在

示例 ​

typescript
const register = async (username: string, email: string, password: string) => {
  const response = await fetch('/api/v1/auth/register', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ username, email, password }),
  });
  
  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.error);
  }
  
  const data = await response.json();
  localStorage.setItem('token', data.token);
  return data;
};

用户登出 ​

POST /api/v1/auth/logout ​

登出当前用户(清除服务端会话)。

请求 ​

http
POST /api/v1/auth/logout
Authorization: Bearer <token>

响应 ​

成功 (200 OK):

json
{
  "message": "Logged out successfully"
}

示例 ​

typescript
const logout = async () => {
  const token = localStorage.getItem('token');
  
  await fetch('/api/v1/auth/logout', {
    method: 'POST',
    headers: { 'Authorization': `Bearer ${token}` },
  });
  
  localStorage.removeItem('token');
};

GitHub OAuth ​

POST /api/v1/auth/github/authorize-url ​

获取 GitHub OAuth 授权 URL。

请求 ​

http
POST /api/v1/auth/github/authorize-url
Content-Type: application/json

{
  "login": "suggested_username",
  "turnstile_token": "optional_cloudflare_token"
}

参数说明:

字段类型必填说明
loginstring❌建议的 GitHub 用户名
turnstile_tokenstring❌Cloudflare Turnstile 验证令牌

响应 ​

成功 (200 OK):

json
{
  "authorize_url": "https://github.com/login/oauth/authorize?client_id=xxx&state=yyy"
}

使用流程 ​

  1. 调用此端点获取授权 URL
  2. 重定向用户到该 URL
  3. 用户授权后,GitHub 会重定向回 callback URL
  4. 前端从 callback URL 获取 code 和 state
  5. 调用 callback 端点完成登录

示例 ​

typescript
const initiateGithubLogin = async () => {
  const response = await fetch('/api/v1/auth/github/authorize-url', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({}),
  });
  
  const data = await response.json();
  window.location.href = data.authorize_url;
};

GET /api/v1/auth/github/callback ​

处理 GitHub OAuth 回调。

请求 ​

http
GET /api/v1/auth/github/callback?code=xxx&state=yyy

参数说明:

参数类型必填说明
codestring✅GitHub 授权码
statestring✅CSRF 防护状态码

响应 ​

成功 (200 OK):

json
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expires_at": "2024-01-02T12:00:00Z",
  "user": {
    "user_id": "550e8400-e29b-41d4-a716-446655440000",
    "username": "johndoe",
    "email": "user@example.com",
    "role": "user",
    "status": "active"
  }
}

说明:

  • 如果 GitHub 用户首次登录,会自动创建账户
  • 邮箱从 GitHub 获取
  • 用户名从 GitHub 登录名生成

密码管理 ​

POST /api/v1/auth/password/forgot ​

请求密码重置邮件。

请求 ​

http
POST /api/v1/auth/password/forgot
Content-Type: application/json

{
  "email": "user@example.com",
  "turnstile_token": "optional_cloudflare_token"
}

参数说明:

字段类型必填说明
emailstring✅注册邮箱
turnstile_tokenstring❌Cloudflare Turnstile 验证令牌

响应 ​

成功 (200 OK):

json
{
  "accepted": true,
  "debug_reset_token": "optional_dev_only_token"
}

说明:

  • 无论邮箱是否存在都返回成功(防止邮箱枚举)
  • 开发环境可能返回 debug_reset_token 用于测试
  • 重置链接有效期 10 分钟

示例 ​

typescript
const forgotPassword = async (email: string) => {
  const response = await fetch('/api/v1/auth/password/forgot', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ email }),
  });
  
  if (!response.ok) {
    throw new Error('Failed to send reset email');
  }
  
  return response.json();
};

POST /api/v1/auth/password/reset ​

使用重置令牌重置密码。

请求 ​

http
POST /api/v1/auth/password/reset
Content-Type: application/json

{
  "token": "reset_token_from_email",
  "new_password": "new_secure_password"
}

参数说明:

字段类型必填说明
tokenstring✅重置令牌(来自邮件)
new_passwordstring✅新密码(至少8位)

响应 ​

成功 (200 OK):

json
{
  "message": "Password reset successfully"
}

错误响应:

  • 400 Bad Request: 令牌无效或已过期
  • 400 Bad Request: 密码不符合要求

示例 ​

typescript
const resetPassword = async (token: string, newPassword: string) => {
  const response = await fetch('/api/v1/auth/password/reset', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ token, new_password: newPassword }),
  });
  
  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.error);
  }
};

用户信息管理 ​

GET /api/v1/me ​

获取当前登录用户的信息。

请求 ​

http
GET /api/v1/me
Authorization: Bearer <token>

响应 ​

成功 (200 OK):

json
{
  "user_id": "550e8400-e29b-41d4-a716-446655440000",
  "username": "johndoe",
  "email": "user@example.com",
  "role": "user",
  "status": "active",
  "last_login_at": "2024-01-01T12:00:00Z"
}

错误响应:

  • 401 Unauthorized: Token 无效或已过期

示例 ​

typescript
const getCurrentUser = async () => {
  const token = localStorage.getItem('token');
  
  const response = await fetch('/api/v1/me', {
    headers: { 'Authorization': `Bearer ${token}` },
  });
  
  if (!response.ok) {
    throw new Error('Failed to fetch user info');
  }
  
  return response.json();
};

PATCH /api/v1/me ​

更新当前用户信息。

请求 ​

http
PATCH /api/v1/me
Authorization: Bearer <token>
Content-Type: application/json

{
  "username": "new_username",
  "email": "new_email@example.com"
}

参数说明:

字段类型必填说明
usernamestring❌新用户名
emailstring❌新邮箱

说明:

  • 至少提供一个字段
  • 新用户名和邮箱不能与已有用户冲突

响应 ​

成功 (200 OK):

json
{
  "user_id": "550e8400-e29b-41d4-a716-446655440000",
  "username": "new_username",
  "email": "new_email@example.com",
  "role": "user",
  "status": "active"
}

错误响应:

  • 400 Bad Request: 参数验证失败
  • 409 Conflict: 用户名或邮箱已被使用

示例 ​

typescript
const updateProfile = async (updates: { username?: string; email?: string }) => {
  const token = localStorage.getItem('token');
  
  const response = await fetch('/api/v1/me', {
    method: 'PATCH',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(updates),
  });
  
  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.error);
  }
  
  return response.json();
};

POST /api/v1/me/password ​

修改当前用户密码。

请求 ​

http
POST /api/v1/me/password
Authorization: Bearer <token>
Content-Type: application/json

{
  "current_password": "old_password",
  "new_password": "new_password"
}

参数说明:

字段类型必填说明
current_passwordstring✅当前密码
new_passwordstring✅新密码(至少8位)

响应 ​

成功 (200 OK):

json
{
  "message": "Password changed successfully"
}

错误响应:

  • 400 Bad Request: 当前密码错误
  • 400 Bad Request: 新密码不符合要求

示例 ​

typescript
const changePassword = async (currentPassword: string, newPassword: string) => {
  const token = localStorage.getItem('token');
  
  const response = await fetch('/api/v1/me/password', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      current_password: currentPassword,
      new_password: newPassword,
    }),
  });
  
  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.error);
  }
};

安全注意事项 ​

密码安全 ​

  • 后端使用 Argon2id 算法哈希密码
  • 密码强度要求:至少 8 个字符
  • 建议使用包含大小写字母、数字和特殊字符的密码

Token 安全 ​

  • JWT Token 有效期为 24 小时
  • Token 应存储在 localStorage 或 sessionStorage
  • 不要在 URL 中传递 Token
  • HTTPS 环境下使用

CSRF 防护 ​

  • GitHub OAuth 使用 state 参数防止 CSRF
  • 敏感操作建议二次验证

防暴力破解 ​

  • Cloudflare Turnstile 人机验证(可选)
  • 建议实施登录频率限制

相关文档 ​

Released under the MIT License.