🎯 派洞察——科研文献智能 RAG 知识库系统

📋 用户管理模块

模块定位:用户管理模块是系统的核心基础模块,负责处理用户的注册、登录和权限控制功能。

🎯 核心目标

  • 身份安全:确保用户身份的安全性和认证可靠性
  • 权限管理:提供灵活的权限管理机制,支持基于角色的访问控制(RBAC)
  • 数据隔离:通过组织标签实现数据访问权限隔离
  • 服务支撑:为其他业务模块提供用户信息支持

📊 一、功能需求

👤 用户注册

📝 功能描述:允许新用户通过用户名和密码注册,注册时默认分配普通用户角色(USER)。

🔧 管理功能:管理员可在后台为新用户分派组织标签(如研究组A、研究组B等),以实现数据权限隔离。

🔐 用户登录

🔑 认证方式:允许用户通过用户名和密码登录系统,登录成功后返回JWT token,后续请求在请求头中携带该token进行身份认证。

📋 Token内容:JWT Token包含用户基本信息和组织标签信息,用于无状态认证。

🛡️ 用户权限控制(RBAC)

🎯 权限模型:通过RBAC实现对不同角色(普通用户和管理员)的功能权限区分,普通用户只能访问自己有权限的数据,管理员可以访问所有数据。

🏷️ 组织管理:管理员可以分配组织标签,如研究组A、研究组B等,以实现数据权限隔离。

🔒 访问控制:普通用户只能访问自己所属组织标签的数据,不能访问其他组织标签的数据。

🔧 安全配置:使用Spring Security配置基于角色的权限控制,确保只有授权角色的用户才能访问相应的接口。

🏷️ 组织标签

🆔 私有标签:用户注册时自动创建并分配个人私有组织标签(格式为:PRIVATE_username),并保存到数据库中。

📍 默认设置:私有组织标签设置为用户默认的组织标签。

🔗 绑定关系:私有组织标签与用户绑定,管理员无法移除。

🛡️ 访问限制:私有组织标签的资源仅限于本人和管理员访问。

📁 数据权限

📋 权限规则:文件访问权限规则如下:

  • 🔒 私有组织标签资源:私有组织标签的资源仅限于本人和管理员访问
  • 👥 组织标签资源:拥有该组织标签的用户可以访问该组织标签下的所有资源
  • 🌍 默认组织标签资源:所有用户可访问
  • 📢 公开标记资源:不受组织标签限制,所有用户均可访问

📤 上传规则:文件上传时自动关联用户的主组织标签(默认为私有标签)。

⚙️ 用户控制:用户可指定上传文件的组织标签和公开权限。

🛠️ 二、技术方案

🔐 身份认证与授权

🎯 JWT:用于无状态身份认证,由JWT生成token,token包含用户信息,服务端验证token,并获取用户信息。

🛡️ Spring Security:用于实现身份认证与授权。

🔒 BCryptPasswordEncoder:用于密码加密存储,确保用户密码的安全性。

🎨 自定义权限过滤器:实现基于组织标签的数据权限控制

💾 数据持久化

🗄️ MySQL:用于存储用户信息,组织标签,数据权限信息。

Redis:用于缓存用户信息,组织标签,数据权限信息。

🚀 Spring Data JPA:用于简化数据库操作,提供CRUD操作。

🧰 辅助工具

🔤 Apache Commons Lang3:提供字符串处理和验证工具。

📝 Lombok:用于简化实体类的编写,通过注解自动生成构造函数、getter/setter方法等。

Validation API:用于验证用户输入数据的合法性,如用户名唯一性、密码格式、密码长度等。

📝 三、关键流程

📋 1. 用户注册

🔄 流程步骤

  1. 📤 接收请求:客户端发送注册请求,包含用户名、密码、邮箱等信息
  2. 数据验证:服务端验证用户输入数据的合法性(如用户名唯一性、密码强度、邮箱格式等)
  3. 🔐 密码加密:使用BCryptPasswordEncoder对密码进行加密
  4. 💾 数据存储:将用户信息保存到数据库中
  5. 🏷️ 创建标签:自动创建用户的私有组织标签(PRIVATE_username)
  6. 🎭 分配角色:为用户分配默认角色(USER)
  7. 📤 返回结果:返回注册成功信息

接口设计

请求URL

1
POST /api/v1/users/register

请求体(JSON)

1
2
3
4
{
"username": "string", // 用户名,唯一
"password": "string" // 密码(明文传输,后端加密存储)
}

成功响应

1
2
3
4
{
"code": 200,
"message": "User registered successfully"
}

失败响应

1
2
3
4
{
"code": 400,
"message": "Username already exists"
}

🔑 2. 用户登录

🔄 流程步骤

  1. 📤 接收请求:客户端发送登录请求,包含用户名和密码
  2. 用户验证:检查用户名是否存在
  3. 🔐 密码验证:使用BCrypt验证密码是否匹配
  4. 🎯 Token生成:生成JWT token,包含用户信息和组织标签
    • 🔑 访问token(access token):用于访问受保护资源,有效期30分钟
    • 🔄 刷新token(refresh token):用于获取新访问token,有效期7天
  5. 📤 返回结果:返回token给客户端

接口设计

请求URL

1
POST /api/v1/users/login

请求体(JSON)

1
2
3
4
{
"username": "string", // 用户名
"password": "string" // 密码(明文传输,后端加密存储)
}

成功响应

1
2
3
4
5
{
"code": 200,
"message": "Login successful",
"token": "JWT_TOKEN_STRING" // JWT token
}

失败响应

1
2
3
4
{
"code": 401, // 失败
"message": "Invalid username or password"
}

👤 3. 获取当前用户信息

🔄 流程步骤

  1. 📤 接收请求:客户端发送请求,请求头中携带JWT token
  2. 🔍 提取Token:服务端从请求头中提取token
  3. 验证Token:验证token的有效性(签名、过期时间等)
  4. 📋 解析信息:从token中解析出username
  5. 🔍 查询详情:根据用户ID查询用户详细信息
  6. 📤 返回结果:返回用户信息

🔌 接口设计

请求URL

1
GET /api/v1/users/me

成功响应

1
2
3
4
5
6
7
8
9
10
11
{
"code": 200,
"message": "Success",
"data": {
"id": 1,
"username": "example_user",
"role": "USER",
"orgTags": ["PRIVATE_example_user", "dept1", "team2"],
"primaryOrg": "PRIVATE_example_user"
}
}

失败响应

1
2
3
4
{
"code": 401,
"message": "Unauthorized"
}

4. 获取用户组织标签

流程

  1. 从 Authorization 中取出 Bearer token
  2. 使用 JwtUtils 提取 username
  3. 调用 userService.getUserOrgTags(username)
  4. 返回组织标签列表与主组织标签

接口设计

请求URL

1
GET /api/v1/users/org-tags

成功响应

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
"code": 200,
"message": "Get user organization tags successful",
"data": {
"orgTags": ["PRIVATE_example_user", "dept1", "team2"],
"primaryOrg": "PRIVATE_example_user",
"orgTagDetails": [
{
"tagId": "PRIVATE_example_user",
"name": "example_user的私人空间",
"description": "用户的私人组织标签,仅用户本人可访问"
},
{
"tagId": "dept1",
"name": "部门1",
"description": "部门1的组织标签"
},
{
"tagId": "team2",
"name": "团队2",
"description": "团队2的组织标签"
}
]
}
}

失败响应

1
2
3
4
{
"code": 401, // 失败
"message": "Unauthorized"
}

5. 设置主组织标签

流程

  1. 从 Authorization 中取出 Bearer token
  2. 使用 JwtUtils 提取 username
  3. 校验参数 primaryOrg 是否存在于 orgTags 中
  4. 调用 userService.setPrimaryOrg(username, primaryOrg),对用户主组织属性进行保存
  5. 返回设置成功响应

接口设计

请求URL

1
PUT /api/v1/users/primary-org

请求体(JSON)

1
2
3
{
"primaryOrg": "string" // 主组织标签
}

成功响应

1
2
3
4
{
"code": 200,
"message": "Primary organization set successfully"
}

失败响应

1
2
3
4
{
"code": 401, // 失败
"message": "Unauthorized"
}

📤 6. 上传文件时的组织标签

🔄 流程步骤

  1. 🆔 获取用户ID:使用 @RequestAttribute(“userId”)(由拦截器提前解析)获取当前用户 ID
  2. 📋 返回信息:返回用户全部 orgTags 与 primaryOrg 字段

接口设计

请求URL

1
GET /api/v1/users/upload-orgs

请求参数

1
userId: string

成功响应

1
2
3
4
5
6
7
8
{
"code": 200,
"message": "获取用户上传组织标签成功",
"data": {
"orgTags": ["tag1", "tag2"],
"primaryOrg": "tagMain"
}
}

失败响应

1
2
3
4
{
"code": 401, // 失败
"message": "Unauthorized"
}

🚪 7. 用户登出

🔄 流程步骤

  1. 🔍 提取Token:从 Authorization 中取出 Bearer token
  2. 👤 解析用户:使用 JwtUtils 提取 username
  3. Token失效:调用 jwtUtils.invalidateToken() 使 token 失效
  4. 📤 返回结果:返回登出成功响应

接口设计

请求URL

1
POST /api/v1/users/logout

成功响应

1
2
3
4
{
"code": 200,
"message": "Logout successful"
}

失败响应

1
{ "code": 400, "message": "Invalid token format" }

🔒 8. 用户全部设备登出

🔄 流程步骤

  1. 🔍 提取Token:从 Authorization 中取出 Bearer token
  2. 👤 解析信息:使用 JwtUtils 解析 token 获取 username 和 userId
  3. 全部失效:调用 jwtUtils.invalidateAllUserTokens(userId) 使所有 token 失效
  4. 📤 返回结果:返回登出成功响应

接口设计

请求URL

1
POST /api/v1/users/logout-all

成功响应

1
{ "code": 200, "message": "Logout from all devices successful" }

失败响应

1
2
3
4
5
# token 格式无效:
{ "code": 400, "message": "Invalid token format" }
# token 无法解析用户名或 userId:
{ "code": 401, "message": "Invalid token" }

🗃️ 四、库表设计

👤 1. 用户表

字段设计

1
2
3
4
5
6
7
8
9
10
| 🔑 字段 | 📋 类型 | 📝 描述 |
| --- | --- | --- |
| `id` | `BIGINT` | 🆔 主键,用户 ID |
| `username` | `varchar(255)` | 👤 用户名,唯一 |
| `password` | `varchar(255)` | 🔒 密码,加密存储 |
| `role` | `ENUM('USER', 'ADMIN')` | 🎭 用户角色,如 USER、ADMIN 等 |
| `org_tags` | `varchar(255)` | 🏷️ 用户所属组织标签,多个用逗号分隔 |
| `primary_org` | `varchar(50)` | 📍 用户主组织标签 |
| `created_at` | `timestamp` | 📅 创建时间 |
| `updated_at` | `timestamp` | 🔄 更新时间 |

建表语句

1
2
3
4
5
6
7
8
9
10
11
CREATE TABLE users (
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '用户唯一标识',
username VARCHAR(255) NOT NULL UNIQUE COMMENT '用户名,唯一',
password VARCHAR(255) NOT NULL COMMENT '加密后的密码',
role ENUM('USER', 'ADMIN') NOT NULL DEFAULT 'USER' COMMENT '用户角色',
org_tags VARCHAR(255) DEFAULT NULL COMMENT '用户所属组织标签,多个用逗号分隔',
primary_org VARCHAR(50) DEFAULT NULL COMMENT '用户主组织标签',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
INDEX idx_username (username) COMMENT '用户名索引'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

🏷️ 2. 组织标签表

字段设计

1
2
3
4
5
6
7
8
9
| 🔑 字段 | 📋 类型 | 📝 描述 |
| --- | --- | --- |
| `tag_id` | `VARCHAR(50)` | 🆔 主键,组织标签 ID |
| `name` | `VARCHAR(100)` | 🏷️ 组织标签名称 |
| `description` | `TEXT` | 📝 组织标签描述 |
| `parent_tag` | `VARCHAR(50)` | 👪 父标签ID |
| `created_by` | `BIGINT` | 👤 创建者ID |
| `created_at` | `TIMESTAMP` | 📅 创建时间 |
| `updated_at` | `TIMESTAMP` | 🔄 更新时间 |

建表语句

1
2
3
4
5
6
7
8
9
10
11
CREATE TABLE organization_tags (
tag_id VARCHAR(50) PRIMARY KEY COMMENT '标签唯一标识',
name VARCHAR(100) NOT NULL COMMENT '标签名称',
description TEXT COMMENT '描述',
parent_tag VARCHAR(50) DEFAULT NULL COMMENT '父标签ID',
created_by BIGINT NOT NULL COMMENT '创建者ID',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
FOREIGN KEY (parent_tag) REFERENCES organization_tags(tag_id) ON DELETE SET NULL,
FOREIGN KEY (created_by) REFERENCES users(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='组织标签表';