派洞察 - 用户管理模块
🎯 派洞察——科研文献智能 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. 用户注册
🔄 流程步骤
- 📤 接收请求:客户端发送注册请求,包含用户名、密码、邮箱等信息
- ✅ 数据验证:服务端验证用户输入数据的合法性(如用户名唯一性、密码强度、邮箱格式等)
- 🔐 密码加密:使用BCryptPasswordEncoder对密码进行加密
- 💾 数据存储:将用户信息保存到数据库中
- 🏷️ 创建标签:自动创建用户的私有组织标签(PRIVATE_username)
- 🎭 分配角色:为用户分配默认角色(USER)
- 📤 返回结果:返回注册成功信息
接口设计
请求URL1
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. 用户登录
🔄 流程步骤
- 📤 接收请求:客户端发送登录请求,包含用户名和密码
- ✅ 用户验证:检查用户名是否存在
- 🔐 密码验证:使用BCrypt验证密码是否匹配
- 🎯 Token生成:生成JWT token,包含用户信息和组织标签
- 🔑 访问token(access token):用于访问受保护资源,有效期30分钟
- 🔄 刷新token(refresh token):用于获取新访问token,有效期7天
- 📤 返回结果:返回token给客户端
接口设计
请求URL1
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. 获取当前用户信息
🔄 流程步骤
- 📤 接收请求:客户端发送请求,请求头中携带JWT token
- 🔍 提取Token:服务端从请求头中提取token
- ✅ 验证Token:验证token的有效性(签名、过期时间等)
- 📋 解析信息:从token中解析出username
- 🔍 查询详情:根据用户ID查询用户详细信息
- 📤 返回结果:返回用户信息
🔌 接口设计
请求URL1
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. 获取用户组织标签
流程
- 从 Authorization 中取出 Bearer token
- 使用 JwtUtils 提取 username
- 调用 userService.getUserOrgTags(username)
- 返回组织标签列表与主组织标签
接口设计
请求URL1
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. 设置主组织标签
流程
- 从 Authorization 中取出 Bearer token
- 使用 JwtUtils 提取 username
- 校验参数 primaryOrg 是否存在于 orgTags 中
- 调用 userService.setPrimaryOrg(username, primaryOrg),对用户主组织属性进行保存
- 返回设置成功响应
接口设计
请求URL1
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. 上传文件时的组织标签
🔄 流程步骤
- 🆔 获取用户ID:使用 @RequestAttribute(“userId”)(由拦截器提前解析)获取当前用户 ID
- 📋 返回信息:返回用户全部 orgTags 与 primaryOrg 字段
接口设计
请求URL1
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. 用户登出
🔄 流程步骤
- 🔍 提取Token:从 Authorization 中取出 Bearer token
- 👤 解析用户:使用 JwtUtils 提取 username
- ❌ Token失效:调用 jwtUtils.invalidateToken() 使 token 失效
- 📤 返回结果:返回登出成功响应
接口设计
请求URL1
POST /api/v1/users/logout
成功响应1
2
3
4{
"code": 200,
"message": "Logout successful"
}
失败响应1
{ "code": 400, "message": "Invalid token format" }
🔒 8. 用户全部设备登出
🔄 流程步骤
- 🔍 提取Token:从 Authorization 中取出 Bearer token
- 👤 解析信息:使用 JwtUtils 解析 token 获取 username 和 userId
- ❌ 全部失效:调用 jwtUtils.invalidateAllUserTokens(userId) 使所有 token 失效
- 📤 返回结果:返回登出成功响应
接口设计
请求URL1
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
11CREATE 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
11CREATE 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='组织标签表';


