Skip to content

Latest commit

 

History

History
602 lines (437 loc) · 20 KB

File metadata and controls

602 lines (437 loc) · 20 KB

kistack 接口文档

本文档描述当前后端代码实际提供的 HTTP 接口。

  • 基础地址:http://localhost:8080
  • 数据格式:除非另有说明,否则使用 JSON
  • 认证方式:Spring Security 会话 Cookie(JSESSIONID)
  • 默认验证码长度:6
  • 默认上传限制:10 MB
  • 英文版本:API.md

1. 通用约定

1.1 会话认证

登录成功后,服务器通过 JSESSIONID Cookie 维护登录状态。访问 /u/** 需要用户具有 USER 或 ADMIN 权限;访问 /back/** 需要 ADMIN 权限。/a/** 和 /p/** 允许匿名访问。

同一账户最多允许一个活动会话。

1.2 CSRF

所有修改状态的现有接口都启用了 CSRF 防护,包括 /a/**、/p/** 下允许匿名访问的 POST 接口。服务端渲染的页面通过以下内容提供令牌:

<meta name="csrf-token" content="...">
<meta name="csrf-header" content="X-CSRF-TOKEN">

JSON 和 multipart 请求应使用页面提供的请求头名称和令牌。HTML 表单应提交隐藏字段 _csrf。

X-CSRF-TOKEN: <token>

CSRF 校验失败由 Spring Security 直接处理,不经过业务异常处理器。

1.3 响应与错误

业务接口成功时返回 200 OK。JSON 接口使用 { "data": ... } 包装;敏感资料修改返回 302 Location: /login。

错误响应同样使用 JSON 包装。参数校验和账户流程异常返回 400 Bad Request;内容操作越权返回 403 Forbidden;文章、评论或公开用户不存在时返回 404 Not Found;同一作者的文章标题冲突返回 409 Conflict;未预期异常返回 500 Internal Server Error。认证和 CSRF 失败可能由 Spring Security 直接处理。

资料修改、内容校验、后台约束以及内容域的 403、404、409 会返回具体业务消息。其他账户流程统一返回 {"data":"Request error"},避免泄露敏感账户状态。上传超过限制时返回 {"data":"Max upload size exceeded"}。

登录表单认证失败由 Spring Security 直接处理,不经过统一异常处理器:服务端返回 302 Location: /login?error,登录页根据 error 查询参数显示统一的失败提示。未认证访问其他受保护接口时,Spring Security 也可能重定向到 /login,而不是返回 JSON 401。

2. 接口概览

方法 路径 认证 CSRF 描述
POST /a/register/verify 公开 必需 发送注册验证码
POST /a/register 公开 必需 注册账户
POST /a/reset-password/verify 公开 必需 发送重置密码验证码
POST /a/reset-password 公开 必需 重置密码
POST /a/login 公开 必需 登录
POST /logout 已认证 必需 退出登录
GET /u/me USER 或 ADMIN 否 获取当前用户资料
POST /u/me/modify/name USER 或 ADMIN 必需 修改用户名
POST /u/me/modify/description USER 或 ADMIN 必需 修改简介
POST /u/me/modify/password USER 或 ADMIN 必需 修改密码
POST /u/me/modify/email/verify USER 或 ADMIN 必需 发送新邮箱验证码
POST /u/me/modify/email USER 或 ADMIN 必需 修改邮箱
POST /u/me/modify/avatar USER 或 ADMIN 必需 上传当前用户头像
GET /back/users ADMIN 否 分页获取用户列表
POST /back/modify/user ADMIN 必需 修改指定用户的完整管理资料
POST /back/create/user ADMIN 必需 创建用户
POST /back/delete/user ADMIN 必需 删除用户
DELETE /back/posts/{postId} ADMIN 必需 删除任意文章及其讨论数据
DELETE /back/comments/{commentId} ADMIN 必需 审核删除任意评论
GET /p/users/{id} 公开 否 获取公开用户资料
GET /p/users/{id}/avatar 公开 否 获取公开用户头像跳转
GET /avatars/{filename} 公开 否 获取头像文件
GET /p/posts 公开 否 按热点分页查询文章
GET /p/posts/hot 公开 否 查询热点文章
GET /p/posts/search/author 公开 否 按作者名模糊搜索文章
GET /p/posts/author/{authorId} 公开 否 按作者 ID 查询文章
GET /p/posts/search/title 公开 否 按标题模糊搜索文章
GET /p/posts/search/tag 公开 否 按标签模糊搜索文章
GET /p/posts/{postId} 公开 否 浏览文章并记录有效浏览量
POST /u/posts USER 或 ADMIN 必需 创建文章
PUT /u/posts/{postId} USER 或 ADMIN 必需 修改自己的文章
DELETE /u/posts/{postId} USER 或 ADMIN 必需 删除自己的文章
GET /p/posts/{postId}/comments 公开 否 查询文章根评论
GET /p/comments/{commentId}/replies 公开 否 查询评论的直接回复
POST /u/posts/{postId}/comments USER 或 ADMIN 必需 发布根评论
POST /u/comments/{commentId}/replies USER 或 ADMIN 必需 回复评论
DELETE /u/comments/{commentId} USER 或 ADMIN 必需 删除自己的评论
PUT /u/posts/{postId}/like USER 或 ADMIN 必需 点赞文章
DELETE /u/posts/{postId}/like USER 或 ADMIN 必需 取消文章点赞
PUT /u/comments/{commentId}/like USER 或 ADMIN 必需 点赞评论
DELETE /u/comments/{commentId}/like USER 或 ADMIN 必需 取消评论点赞

3. 认证接口

3.1 发送注册验证码

POST /a/register/verify

发送注册场景的邮件验证码。邮箱必须尚未注册。

Content-Type: application/json
X-CSRF-TOKEN: <token>
{
  "email": "user@example.com",
  "scene": "REGISTER"
}

字段要求:

  • email:必填并且必须匹配有效邮箱格式。
  • scene:必须为 REGISTER。

成功响应:200 OK,application/json

{
  "data": null
}

3.2 注册账户

POST /a/register

使用注册验证码创建账户。注册成功后不会自动登录。

Content-Type: application/json
X-CSRF-TOKEN: <token>
{
  "username": "alice",
  "password": "secret123",
  "email": "user@example.com",
  "verificationCode": "A1B2C3"
}

字段要求:

  • username:必填、非空、不得包含普通空格、最多 32 个字符,并且必须唯一。
  • password:必填、不得包含普通空格,长度为 6 至 32 个字符。
  • email:必填、格式有效并且必须唯一。
  • verificationCode:必填,长度必须符合验证码配置,默认为 6。

成功响应:200 OK,application/json

{
  "data": {
    "message": "Register successfully",
    "name": "alice"
  }
}

3.3 发送重置密码验证码

POST /a/reset-password/verify

向已注册邮箱发送高风险操作验证码。

Content-Type: application/json
X-CSRF-TOKEN: <token>
{
  "email": "user@example.com",
  "scene": "HIGH_RISK"
}

字段要求:

  • email:必填、格式有效,并且必须属于现有账户。
  • scene:必须为 HIGH_RISK。

成功响应:200 OK,application/json

{
  "data": null
}

3.4 重置密码

POST /a/reset-password

验证码和邮箱必须属于同一账户。成功后验证码失效,并通过会话注册表使匹配到的已有会话过期。

Content-Type: application/json
X-CSRF-TOKEN: <token>
{
    "email": "user@example.com",
  "newPassword": "newSecret123",
  "verificationCode": "D4E5F6"
}

字段要求:

  • email:必填、格式有效,并且必须属于现有账户。
  • newPassword:必填、不得包含普通空格,长度为 6 至 32 个字符。
  • verificationCode:必填,长度必须符合验证码配置。

成功响应:200 OK,application/json

{
  "data": "Password reset successfully"
}

3.5 登录

POST /a/login

该接口由 Spring Security 表单登录提供,不接收 JSON。

Content-Type: application/x-www-form-urlencoded
username=alice&password=secret123&_csrf=<token>
  • 成功:设置会话 Cookie,并以 302 重定向至 /dashboard。
  • 失败:以 302 Location: /login?error 重定向回登录页。GET /login?error 返回登录页面,并显示“用户名或密码错误,请重试”;失败响应不是 JSON。

3.6 退出登录

POST /logout

需要有效会话和 CSRF 表单字段。

_csrf=<token>

成功后使当前会话失效,并默认以 302 重定向至 /login?logout。

4. 用户资料接口

4.1 获取当前用户资料

GET /u/me

认证:需要 USER 或 ADMIN 权限。

成功响应:200 OK,application/json

{
  "data": {
    "userId": 1,
    "userName": "alice",
    "userEmail": "user@example.com",
    "description": "Hello",
    "createdAt": "2026-07-29T12:00:00",
    "enabled": true
  }
}

createdAt 使用 Jackson 对 LocalDateTime 的默认 ISO-8601 JSON 表示。

4.2 修改用户名

POST /u/me/modify/name,请求体为 {"newName":"alice2"}。目标用户始终取自当前登录会话。成功后返回 302 Location: /login。

4.3 修改简介

POST /u/me/modify/description,请求体为 {"newDescription":"简介"}。

4.4 修改密码

POST /u/me/modify/password,请求体为 {"oldPassword":"old","newPassword":"newSecret"}。成功后返回 302 Location: /login。

4.5 修改邮箱

先使用 {"email":"new@example.com","scene":"RESET_EMAIL"} 调用 /u/me/modify/email/verify,再向 /u/me/modify/email 提交 {"email":"new@example.com","password":"currentPassword","verificationCode":"ABC123"}。成功后返回 302 Location: /login。

4.6 修改当前用户头像

POST /u/me/modify/avatar

认证:需要 USER 或 ADMIN 权限。

Content-Type: multipart/form-data; boundary=...
X-CSRF-TOKEN: <token>
名称 类型 必填 描述
file 文件 是 新头像文件

要求:

  • 文件必须非空且 MIME 类型以 image/ 开头。
  • 后端会解析实际图片内容,不只信任文件扩展名。
  • 支持 PNG、JPEG 和 GIF。
  • 默认单文件和请求总大小上限均为 10 MB。
  • 账户必须处于启用状态。

成功响应:200 OK,响应体为 {"data":null}。

5. 管理员接口

5.1 分页获取用户列表

GET /back/users

认证:仅限 ADMIN。支持 Spring Data Pageable 查询参数:

参数 示例 描述
page 0 从 0 开始的页码
size 20 每页记录数,服务端限制为 1..100
sort id,asc 排序字段与方向;可重复传递

示例:GET /back/users?page=0&size=20&sort=id,asc

成功响应的 data 是稳定的分页对象:

{
  "data": {
    "content": [
      {
        "id": 2,
        "username": "alice",
        "email": "alice@example.com",
        "avatarId": 2,
        "role": "USER",
        "enabled": true,
        "createdAt": "2026-07-29T12:00:00",
        "updatedAt": "2026-07-30T12:00:00"
      }
    ],
    "page": 0,
    "size": 20,
    "totalPages": 1,
    "totalElements": 1,
    "first": true,
    "last": true
  }
}

5.2 修改指定用户

POST /back/modify/user

认证:仅限 ADMIN。需要 JSON 和 CSRF 请求头。每次保存必须携带全部五个字段,不能只发送发生变化的字段:

{
  "id": 2,
  "username": "alice",
  "email": "alice@example.com",
  "role": "USER",
  "enabled": true
}

字段要求:

  • id:必填,必须对应现有用户。
  • username:必填、非空、不得包含 @ 或普通空格,最多 32 个字符。
  • email:必填、非空,必须匹配配置的邮箱正则。
  • role:必填,只能为 USER 或 ADMIN。
  • enabled:必填布尔值。DTO 使用基本类型,遗漏时会被绑定为 false,因此客户端不得省略。

系统始终要求至少存在一个处于启用状态的 ADMIN;违反该约束时事务回滚。修改成功后,目标用户在会话注册表中匹配到的所有会话会被标记为过期。若管理员修改自己的账户,当前页面会跳转到登录页。

成功响应:200 OK,data 为修改后的用户视图,字段与列表项一致。

5.3 创建用户

POST /back/create/user

认证:仅限 ADMIN。需要 JSON 和 CSRF 请求头。请求必须携带全部五个字段:

{
  "username": "alice",
  "email": "alice@example.com",
  "password": "secret1",
  "role": "USER",
  "enabled": true
}

字段要求:

  • username:必填、非空、不得包含 @ 或普通空格,最多 32 个字符。
  • email:必填、非空,必须匹配配置的邮箱正则。
  • password:必填、非空、不得包含普通空格,长度为 6 至 64 个字符。
  • role:必填,只能为 USER 或 ADMIN。
  • enabled:必须显式为 true;当前后端不允许直接创建停用用户。

密码使用 BCrypt 编码后存储。成功响应为 200 OK,data 是新用户的用户视图,不返回密码或密码哈希。

5.4 删除用户

POST /back/delete/user

认证:仅限 ADMIN。需要 JSON 和 CSRF 请求头。请求使用待删除用户最后一次从服务器取得的完整快照:

{
  "id": 2,
  "username": "alice",
  "email": "alice@example.com",
  "role": "USER",
  "enabled": true
}

id、username、email 和 role 必须与数据库中的用户一致,否则请求失败。后台页面也会携带 enabled。删除成功后目标用户的匹配会话会被标记为过期,响应为 {"data":true}。服务会检查系统中是否仍有启用的管理员。

5.5 删除文章

DELETE /back/posts/{postId}

认证:仅限 ADMIN。必须携带 CSRF 令牌,请求无正文。管理员可以删除任意作者的文章。整个操作在一个事务中删除文章下的评论、评论点赞、文章点赞、标签记录和浏览去重缓存,随后文章不可再访问。

成功返回 200 OK;文章不存在时返回 404 Not Found。

5.6 删除评论

DELETE /back/comments/{commentId}

认证:仅限 ADMIN。必须携带 CSRF 令牌,请求无正文。管理员可以删除任意发布者的评论。叶子评论执行物理删除;存在回复的评论转换为与用户自删相同的删除占位节点,保证回复仍可访问。点赞和活跃评论计数在同一事务中更新。对仍存在的软删除占位节点重复请求为幂等成功。

成功返回 200 OK;评论不存在时返回 404 Not Found。

6. 公开资料与头像接口

6.1 获取公开资料

GET /p/users/{id}

允许匿名访问且不需要 CSRF 令牌。用户不存在或已停用时返回 404 Not Found。成功响应使用统一 data 包装:

{
  "data": {
    "userId": 2,
    "userName": "alice",
    "description": "后端开发者",
    "avatarUrl": "/p/users/2/avatar",
    "postCount": 3,
    "createdAt": "2026-07-29T12:00:00"
  }
}

6.2 获取公开用户头像

GET /p/users/{id}/avatar

返回 302 Found,Location 指向用户当前头像或默认头像。用户不存在或已停用时返回 404 Not Found。

6.3 获取头像文件

GET /avatars/{filename}

公开访问。从配置的 kistack.data.path/avatars 目录读取文件。Content-Type 根据静态资源处理器和文件类型确定。

GET /avatars/default.png

7. 页面路由

以下路由返回 Thymeleaf HTML 页面,不是 JSON 接口。

方法 路径 访问权限 页面
GET /login 公开 登录页
GET /register 公开 注册页
GET /reset-password 公开 重置密码页
GET / 或 /index 公开 文章首页与搜索页
GET /posts/{postId} 公开 文章详情与评论页
GET /users/{userId} 公开 用户公开主页
GET /dashboard USER 或 ADMIN 用户资料页
GET /editor USER 或 ADMIN 新建文章编辑器
GET /editor/{postId} USER 或 ADMIN 修改文章编辑器
GET /back/dashboard ADMIN 后台用户管理页

GET /favicon.svg 是公开静态资源。

8. 文章与评论接口

所有列表接口都使用统一 data 包装,并返回稳定分页结构:

{
  "data": {
    "content": [],
    "page": 0,
    "size": 20,
    "totalElements": 0,
    "totalPages": 0,
    "first": true,
    "last": true
  }
}

文章列表、搜索结果、评论和回复均固定按照 hotScore DESC、createdAt DESC、id DESC 排序。page 默认 0,size 默认 20 且最大为 100。热点文章接口使用 limit,默认 20 且最大为 50。

8.1 查询文章

方法与路径 查询参数
GET /p/posts page、size
GET /p/posts/hot limit
GET /p/posts/search/author keyword、page、size
GET /p/posts/author/{authorId} page、size
GET /p/posts/search/title keyword、page、size
GET /p/posts/search/tag keyword、page、size
GET /p/posts/{postId} 无

英文搜索忽略大小写,%、_ 和 ! 按普通字符处理。列表响应不返回完整正文;浏览单篇文章会返回正文,并在配置的去重窗口内最多为同一访问者增加一次浏览量。列表和搜索不会增加浏览量。

旧的 /p/post/pid={id}、/p/post/title={title} 等文章查询路径已经删除。

8.2 创建、修改和删除文章

POST /u/posts 与 PUT /u/posts/{postId} 使用以下请求体:

{
  "title": "Spring Data JPA notes",
  "content": "Article content...",
  "tags": ["spring", "jpa", "sqlite"]
}

作者身份始终来自当前登录会话。标题最长 200 个字符,正文最长 100000 个字符,每篇文章必须有 1 至 10 个标签,每个标签最长 64 个字符。标签会进行 trim、转小写和去重。只有作者本人可以修改或删除文章;删除文章会同步清理评论、点赞和标签数据。

8.3 评论与回复

GET /p/posts/{postId}/comments 查询文章根评论,GET /p/comments/{commentId}/replies 查询某条评论的直接回复。发布评论和回复均使用:

{
  "content": "评论内容"
}

评论内容最长 500 个字符。回复的 postId 与 respondentId 完全由父评论推导,客户端不能指定。没有回复的评论会物理删除;已有回复的评论会保留为删除占位节点,避免回复链断裂。用户只能删除自己发布的评论。

8.4 点赞与热点值

文章和评论的点赞、取消点赞接口均为幂等操作。数据库唯一记录保证同一用户不会重复增加计数,重复取消点赞也不会产生负数。成功响应如下:

{
  "data": {
    "liked": true,
    "likeCount": 12
  }
}

文章热点值由对数化的浏览、点赞、评论信号和时间衰减共同计算;评论热点值使用点赞、直接回复和时间衰减。互动发生后立即刷新热点,并由后台任务定期执行时间衰减刷新。

9. 配置说明

以下行为可以通过配置或环境变量改变,因此部署环境可能与本文档中的默认值不同:

  • 初始管理员密码:KISTACK_ADMIN_PASSWORD(必填,无默认值)
  • 管理员重置开关:KISTACK_ADMIN_RESET_ENABLED(默认 false)
  • 验证码长度:kistack.email.verification.verification-code-length
  • 邮箱格式正则:kistack.email.from.email-format-regex
  • 单文件大小:spring.servlet.multipart.max-file-size
  • 请求总大小:spring.servlet.multipart.max-request-size
  • 数据目录:kistack.data.path
  • 默认头像:kistack.data.default-avatar
  • 文章浏览去重窗口:kistack.caffeine.post-view-deduplicate-minutes
  • 文章浏览缓存容量:kistack.caffeine.post-view-maximum-size
  • 热点值刷新间隔:kistack.hot-score.refresh-interval-ms
  • 热点值刷新批量大小:kistack.hot-score.refresh-batch-size