CarefreeCMS 文档CarefreeCMS 文档
指南
  • 内容管理
  • 多站点管理
  • AI文章生成
  • SEO优化
  • 静态化生成
API
  • FAQ
  • 更新日志
  • 贡献指南
  • v1.3.0
  • v1.2.0
  • v1.1.0
GitHub
指南
  • 内容管理
  • 多站点管理
  • AI文章生成
  • SEO优化
  • 静态化生成
API
  • FAQ
  • 更新日志
  • 贡献指南
  • v1.3.0
  • v1.2.0
  • v1.1.0
GitHub
  • API 文档

    • API 文档
    • 认证接口
    • 文章接口
    • 分类接口
    • 标签接口
    • 媒体接口
    • 评论接口
    • 用户接口

认证接口

用户认证相关的 API 接口,包括登录、注册、退出、Token 刷新等。

用户登录

接口信息

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

请求参数

参数类型必填说明
usernamestring是用户名或邮箱
passwordstring是密码
captchastring否验证码(启用时必填)
rememberboolean否是否记住登录

请求示例

{
  "username": "admin",
  "password": "admin123",
  "captcha": "ABCD",
  "remember": true
}

响应参数

参数类型说明
codeinteger状态码
messagestring提示信息
data.tokenstringJWT Token
data.expireinteger过期时间(秒)
data.userobject用户信息

响应示例

成功响应(200)

{
  "code": 200,
  "message": "登录成功",
  "data": {
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJjbXNfc3lzdGVtIiwiYXVkIjoiY21zX3VzZXIiLCJpYXQiOjE3MDUzMTcwMDAsImV4cCI6MTcwNTMyNDIwMCwiZGF0YSI6eyJpZCI6MSwidXNlcm5hbWUiOiJhZG1pbiIsInJvbGVfaWQiOjF9fQ.xxxxx",
    "expire": 7200,
    "user": {
      "id": 1,
      "username": "admin",
      "email": "admin@example.com",
      "nickname": "管理员",
      "avatar": "https://example.com/avatar/admin.jpg",
      "role": {
        "id": 1,
        "name": "超级管理员"
      },
      "permissions": [
        "article.view",
        "article.create",
        "article.update",
        "article.delete"
      ]
    }
  },
  "timestamp": 1705317000
}

失败响应(401)

{
  "code": 401,
  "message": "用户名或密码错误",
  "timestamp": 1705317000
}

验证码错误(400)

{
  "code": 400,
  "message": "验证码错误",
  "timestamp": 1705317000
}

账号被禁用(403)

{
  "code": 403,
  "message": "账号已被禁用",
  "timestamp": 1705317000
}

代码示例

JavaScript (Axios)

import axios from 'axios'

const login = async (username, password) => {
  try {
    const response = await axios.post('/api/auth/login', {
      username,
      password,
      remember: true
    })

    if (response.data.code === 200) {
      // 保存 Token
      localStorage.setItem('token', response.data.data.token)
      localStorage.setItem('user', JSON.stringify(response.data.data.user))

      return response.data
    }
  } catch (error) {
    console.error('登录失败:', error)
    throw error
  }
}

// 使用
login('admin', 'admin123')
  .then(data => {
    console.log('登录成功:', data)
  })
  .catch(error => {
    console.error('登录失败:', error)
  })

PHP (cURL)

<?php
$url = 'http://your-domain.com/api/auth/login';

$data = [
    'username' => 'admin',
    'password' => 'admin123',
    'remember' => true,
];

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
]);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response, true);

if ($result['code'] === 200) {
    $token = $result['data']['token'];
    echo "登录成功,Token: $token\n";
} else {
    echo "登录失败: " . $result['message'] . "\n";
}

用户注册

接口信息

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

请求参数

参数类型必填说明
usernamestring是用户名(3-20字符)
passwordstring是密码(6-20字符)
password_confirmstring是确认密码
emailstring是邮箱地址
nicknamestring否昵称
captchastring是验证码
agreeboolean是同意服务条款

请求示例

{
  "username": "newuser",
  "password": "password123",
  "password_confirm": "password123",
  "email": "newuser@example.com",
  "nickname": "新用户",
  "captcha": "ABCD",
  "agree": true
}

响应示例

成功响应(201)

{
  "code": 201,
  "message": "注册成功",
  "data": {
    "id": 10,
    "username": "newuser",
    "email": "newuser@example.com",
    "nickname": "新用户"
  },
  "timestamp": 1705317000
}

用户名已存在(400)

{
  "code": 400,
  "message": "用户名已被使用",
  "timestamp": 1705317000
}

邮箱已注册(400)

{
  "code": 400,
  "message": "邮箱已被注册",
  "timestamp": 1705317000
}

验证失败(422)

{
  "code": 422,
  "message": "数据验证失败",
  "errors": {
    "username": ["用户名长度必须在3-20个字符之间"],
    "password": ["两次密码输入不一致"],
    "email": ["邮箱格式不正确"]
  },
  "timestamp": 1705317000
}

用户退出

接口信息

POST /api/auth/logout
Authorization: Bearer {token}

请求参数

无

响应示例

成功响应(200)

{
  "code": 200,
  "message": "退出成功",
  "timestamp": 1705317000
}

代码示例

const logout = async () => {
  try {
    const token = localStorage.getItem('token')

    await axios.post('/api/auth/logout', {}, {
      headers: {
        'Authorization': `Bearer ${token}`
      }
    })

    // 清除本地数据
    localStorage.removeItem('token')
    localStorage.removeItem('user')

    // 跳转到登录页
    window.location.href = '/login'
  } catch (error) {
    console.error('退出失败:', error)
  }
}

Token 刷新

接口信息

POST /api/auth/refresh
Authorization: Bearer {token}

请求参数

无

响应示例

成功响应(200)

{
  "code": 200,
  "message": "Token刷新成功",
  "data": {
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.xxxxx",
    "expire": 7200
  },
  "timestamp": 1705317000
}

Token 已过期(401)

{
  "code": 10002,
  "message": "Token已过期,请重新登录",
  "timestamp": 1705317000
}

代码示例

// 自动刷新 Token
const refreshToken = async () => {
  try {
    const token = localStorage.getItem('token')

    const response = await axios.post('/api/auth/refresh', {}, {
      headers: {
        'Authorization': `Bearer ${token}`
      }
    })

    if (response.data.code === 200) {
      // 更新 Token
      localStorage.setItem('token', response.data.data.token)
      return response.data.data.token
    }
  } catch (error) {
    // Token 刷新失败,跳转到登录页
    window.location.href = '/login'
  }
}

// Axios 响应拦截器
axios.interceptors.response.use(
  response => response,
  async error => {
    if (error.response?.status === 401) {
      // Token 过期,尝试刷新
      const newToken = await refreshToken()
      if (newToken) {
        // 重试原请求
        error.config.headers.Authorization = `Bearer ${newToken}`
        return axios(error.config)
      }
    }
    return Promise.reject(error)
  }
)

获取当前用户信息

接口信息

GET /api/auth/user
Authorization: Bearer {token}

请求参数

无

响应示例

成功响应(200)

{
  "code": 200,
  "message": "获取成功",
  "data": {
    "id": 1,
    "username": "admin",
    "email": "admin@example.com",
    "nickname": "管理员",
    "avatar": "https://example.com/avatar/admin.jpg",
    "phone": "13800138000",
    "status": 1,
    "role": {
      "id": 1,
      "name": "超级管理员"
    },
    "permissions": [
      "article.*",
      "category.*",
      "system.*"
    ],
    "create_time": "2023-01-01 00:00:00",
    "last_login_time": "2024-01-15 14:30:25",
    "last_login_ip": "192.168.1.100"
  },
  "timestamp": 1705317000
}

修改密码

接口信息

POST /api/auth/change-password
Authorization: Bearer {token}
Content-Type: application/json

请求参数

参数类型必填说明
old_passwordstring是原密码
new_passwordstring是新密码
new_password_confirmstring是确认新密码

请求示例

{
  "old_password": "old123456",
  "new_password": "new123456",
  "new_password_confirm": "new123456"
}

响应示例

成功响应(200)

{
  "code": 200,
  "message": "密码修改成功,请重新登录",
  "timestamp": 1705317000
}

原密码错误(400)

{
  "code": 400,
  "message": "原密码不正确",
  "timestamp": 1705317000
}

忘记密码

发送重置邮件

接口信息

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

请求参数

参数类型必填说明
emailstring是注册邮箱
captchastring是验证码

请求示例

{
  "email": "admin@example.com",
  "captcha": "ABCD"
}

响应示例

{
  "code": 200,
  "message": "重置邮件已发送,请查收",
  "timestamp": 1705317000
}

重置密码

接口信息

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

请求参数

参数类型必填说明
tokenstring是邮件中的重置Token
passwordstring是新密码
password_confirmstring是确认密码

请求示例

{
  "token": "abc123def456",
  "password": "newpassword123",
  "password_confirm": "newpassword123"
}

响应示例

{
  "code": 200,
  "message": "密码重置成功,请使用新密码登录",
  "timestamp": 1705317000
}

验证 Token

接口信息

POST /api/auth/verify
Authorization: Bearer {token}

请求参数

无

响应示例

Token 有效(200)

{
  "code": 200,
  "message": "Token有效",
  "data": {
    "valid": true,
    "expire_at": "2024-01-15 16:30:25"
  },
  "timestamp": 1705317000
}

Token 无效(401)

{
  "code": 10001,
  "message": "Token无效",
  "data": {
    "valid": false
  },
  "timestamp": 1705317000
}

获取验证码

图形验证码

接口信息

GET /api/captcha

响应示例

{
  "code": 200,
  "data": {
    "key": "captcha_abc123",
    "image": "data:image/png;base64,iVBORw0KGgoAAAANS..."
  },
  "timestamp": 1705317000
}

短信验证码

接口信息

POST /api/sms/send
Content-Type: application/json

请求参数

参数类型必填说明
phonestring是手机号码
typestring是类型(register/login/reset)
captchastring是图形验证码

请求示例

{
  "phone": "13800138000",
  "type": "register",
  "captcha": "ABCD"
}

响应示例

{
  "code": 200,
  "message": "短信验证码已发送",
  "data": {
    "expire": 300
  },
  "timestamp": 1705317000
}

错误码

错误码说明
401未认证或认证失败
403账号被禁用
10001Token 无效
10002Token 已过期
10003用户不存在
10004密码错误
10005验证码错误
10006账号已被锁定

安全建议

Token 存储

推荐方式

// 存储在 localStorage(推荐用于 SPA)
localStorage.setItem('token', token)

// 存储在 Cookie(推荐用于传统网站)
document.cookie = `token=${token}; path=/; secure; httpOnly`

不推荐

// ✗ 不要存储在全局变量
window.token = token

// ✗ 不要存储在 sessionStorage(刷新会丢失)
sessionStorage.setItem('token', token)

HTTPS

生产环境必须使用 HTTPS:

server {
    listen 443 ssl http2;
    server_name api.example.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    # 其他配置...
}

Token 过期处理

// 请求拦截器:添加 Token
axios.interceptors.request.use(config => {
  const token = localStorage.getItem('token')
  if (token) {
    config.headers.Authorization = `Bearer ${token}`
  }
  return config
})

// 响应拦截器:处理过期
axios.interceptors.response.use(
  response => response,
  async error => {
    const originalRequest = error.config

    // Token 过期
    if (error.response?.status === 401 && !originalRequest._retry) {
      originalRequest._retry = true

      try {
        // 刷新 Token
        const newToken = await refreshToken()
        originalRequest.headers.Authorization = `Bearer ${newToken}`
        return axios(originalRequest)
      } catch (refreshError) {
        // 刷新失败,跳转登录
        window.location.href = '/login'
        return Promise.reject(refreshError)
      }
    }

    return Promise.reject(error)
  }
)

防止暴力破解

后端限流

// 登录失败次数限制
$attempts = Cache::get('login_attempts_' . $username, 0);

if ($attempts >= 5) {
    return json([
        'code' => 429,
        'message' => '登录失败次数过多,请30分钟后重试'
    ]);
}

// 验证密码
if (!$this->checkPassword($password)) {
    Cache::set('login_attempts_' . $username, $attempts + 1, 1800);
    return json([
        'code' => 401,
        'message' => '用户名或密码错误'
    ]);
}

前端延迟

let loginAttempts = 0

const login = async (username, password) => {
  // 失败后延迟重试
  if (loginAttempts > 0) {
    await new Promise(resolve => {
      setTimeout(resolve, loginAttempts * 1000)
    })
  }

  try {
    const result = await api.login(username, password)
    loginAttempts = 0 // 重置
    return result
  } catch (error) {
    loginAttempts++
    throw error
  }
}

相关接口

  • 用户管理接口
  • 权限验证
  • 系统安全
在 GitHub 上编辑此页
Prev
API 文档
Next
文章接口