KnowFlow 项目学习笔记(三):安全 + 部署深度解析

写在前面:本学习笔记基于 KnowFlow 项目源码逐行解析,深度讲解安全机制(JWT 认证、RBAC 权限控制、组织标签授权)和部署方案(K8s、Prometheus 监控)。并指出源码里的 3 处严重问题(❗❗ 标记),给出修复方案。适合面试前深度学习,确保”傻子都能懂”。


一、安全机制概述

傻子都能懂的解释

想象你是一个网站的老板:

  • 认证(Authentication):确认用户是谁(比如”张三”登录了)
  • 授权(Authorization):确认用户能做什么(比如”张三”是”普通用户”,只能看普通文档;”李四”是”管理员”,能看所有文档)

KnowFlow 的安全机制

  1. JWT 认证:用户登录后,服务器返回一个 token(类似”通行证”),后续请求都带上这个 token
  2. RBAC 权限控制:基于角色的访问控制(比如”普通用户”只能看文档,”管理员”能管理知识库)
  3. 组织标签授权:基于组织标签的权限控制(比如”技术部”的人只能看”技术部”的文档)

二、源码解析:SecurityConfig.java

文件位置PaiSmart-zuzhi/src/main/java/com/yizhaoqi/smartpai/config/SecurityConfig.java

2.1 Spring Security 配置:securityFilterChain() 方法

源码(第 39-91 行)

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
try {
// 禁用CSRF保护
http.csrf(csrf -> csrf.disable())
// 配置请求的授权规则
.authorizeHttpRequests(authorize -> authorize
// 允许静态资源访问
.requestMatchers("/", "/test.html", "/static/test.html", "/static/**", "/*.js", "/*.css", "/*.ico").permitAll()
// 允许 Swagger/OpenAPI 文档访问
.requestMatchers("/swagger-ui/**", "/v3/api-docs/**", "/swagger-ui.html").permitAll()
// 允许 Actuator 监控端点访问(Prometheus 采集)
.requestMatchers("/actuator/**").permitAll()
// 允许 WebSocket 连接
.requestMatchers("/chat/**", "/ws/**").permitAll()
// 允许登录注册接口
.requestMatchers("/api/v1/users/register", "/api/v1/users/login").permitAll()
// 允许测试接口
.requestMatchers("/api/v1/test/**").permitAll()
// 文件上传和下载相关接口 - 普通用户和管理员都可访问
.requestMatchers("/api/v1/upload/**", "/api/v1/parse", "/api/v1/documents/download", "/api/v1/documents/preview").hasAnyRole("USER", "ADMIN")
// 对话历史相关接口 - 用户只能查看自己的历史,管理员可以查看所有
.requestMatchers("/api/v1/users/conversation/**").hasAnyRole("USER", "ADMIN")
// 搜索接口 - 普通用户和管理员都可访问
.requestMatchers("/api/search/**").hasAnyRole("USER", "ADMIN")
// 聊天相关接口 - WebSocket停止Token获取 (允许匿名访问)
.requestMatchers("/api/chat/websocket-token").permitAll()
// 管理员专属接口 - 知识库管理、系统状态、用户活动监控
.requestMatchers("/api/v1/admin/**").hasRole("ADMIN")
// 用户组织标签管理接口
.requestMatchers("/api/v1/users/primary-org").hasAnyRole("USER", "ADMIN")
// 其他请求需要认证
.anyRequest().authenticated())
// 配置会话管理策略
// 设置会话创建策略为STATELESS,表示不会创建会话,通常用于无状态的API应用
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
// 添加JWT认证过滤器
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
// 添加组织标签授权过滤器
.addFilterAfter(orgTagAuthorizationFilter, JwtAuthenticationFilter.class);

// 记录安全配置加载成功的信息
logger.info("Security configuration loaded successfully.");
// 返回配置好的安全过滤链
return http.build();
} catch (Exception e) {
// 记录配置安全过滤链失败的错误信息
logger.error("Failed to configure security filter chain", e);
// 抛出异常,以便外部处理
throw e;
}
}

逐行解析(傻子都能懂版)

  1. 第 43 行http.csrf(csrf -> csrf.disable())

    • 禁用 CSRF 保护
    • 为什么禁用? 因为用的是 JWT(无状态),不需要 CSRF token
  2. 第 45-71 行:配置请求的授权规则

    • .permitAll():允许所有人访问(不需要登录)
    • .hasAnyRole("USER", "ADMIN"):需要”USER”或”ADMIN”角色
    • .hasRole("ADMIN"):需要”ADMIN”角色
    • .authenticated():需要登录(任何角色都可以)
  3. 第 74-75 行:配置会话管理策略

    • SessionCreationPolicy.STATELESS:不创建会话(每次请求都带 JWT token)
  4. 第 77 行:添加 JWT 认证过滤器

    • 在每个请求之前,先验证 JWT token(确认用户是谁)
  5. 第 79 行:添加组织标签授权过滤器

    • 在 JWT 认证之后,检查用户是否有权限访问该文档(基于组织标签)

三、JWT 认证机制

3.1 什么是 JWT?

傻子都能懂的解释

JWT(JSON Web Token) 是一个”通行证”:

  • 用户登录后,服务器生成一个 JWT(包含用户 ID、角色、过期时间)
  • 用户后续请求都带上这个 JWT(放在 HTTP Header 里:Authorization: Bearer xxx
  • 服务器验证 JWT 是否合法(签名是否正确、是否过期)
  • 如果合法,就知道用户是谁(不需要查数据库)

JWT 的结构

1
Header.Payload.Signature

比如:

1
eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjEwMDF9.xxx
  • Header:加密算法(比如 HMAC256)
  • Payload:用户信息(比如 {"userId": 1001}
  • Signature:签名(用来验证 JWT 是否被篡改)

3.2 JWT 认证流程

流程

  1. 用户登录:POST /api/v1/users/login,传用户名和密码
  2. 服务器验证用户名和密码(查数据库)
  3. 如果正确,生成 JWT token(包含用户 ID、角色、过期时间)
  4. 返回 JWT token 给前端
  5. 前端后续请求都带上 JWT token(Authorization: Bearer xxx
  6. 后端用 JWT 认证过滤器验证 token(确认用户是谁)

四、RBAC 权限控制

4.1 什么是 RBAC?

傻子都能懂的解释

RBAC(Role-Based Access Control) 是基于角色的访问控制:

  • 用户:比如”张三”、”李四”
  • 角色:比如”普通用户”、”管理员”
  • 权限:比如”查看文档”、”上传文档”、”删除文档”

关系

  • 用户和角色是多对多(一个用户可以有多个角色,一个角色可以分配给多个用户)
  • 角色和权限是多对多(一个角色可以有多个权限,一个权限可以分配给多个角色)

KnowFlow 的角色

  • ROLE_USER:普通用户(能上传文档、搜索文档)
  • ROLE_ADMIN:管理员(能管理知识库、查看系统状态)

4.2 RBAC 的实现

数据库表设计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
-- 用户表
CREATE TABLE users (
id BIGINT PRIMARY KEY,
username VARCHAR(255),
password VARCHAR(255),
role VARCHAR(50) -- 'ROLE_USER' 或 'ROLE_ADMIN'
);

-- 权限表(可选,如果权限很多的话)
CREATE TABLE permissions (
id BIGINT PRIMARY KEY,
name VARCHAR(255) -- 'view_document', 'upload_document', etc.
);

-- 角色权限表(可选)
CREATE TABLE role_permissions (
role VARCHAR(50),
permission_id BIGINT
);

Spring Security 配置

1
2
.requestMatchers("/api/v1/upload/**").hasAnyRole("USER", "ADMIN")
.requestMatchers("/api/v1/admin/**").hasRole("ADMIN")

五、组织标签授权

5.1 什么是组织标签?

傻子都能懂的解释

组织标签就是”部门”(比如”技术部”、”产品部”):

  • 每个文档都有一个组织标签(比如”技术部”的文档)
  • 每个用户都有一个组织标签(比如”技术部”的用户)
  • 用户只能看到自己所在部门的文档(除非是公开文档)

层级关系

  • 比如”技术部”下面有”前端组”、”后端组”
  • 如果用户属于”技术部”,他能看到”技术部”、”前端组”、”后端组”的所有文档

5.2 组织标签授权的实现

过滤器OrgTagAuthorizationFilter

流程

  1. 用户请求访问文档:GET /api/v1/documents/123
  2. 过滤器获取用户的组织标签(比如”技术部”)
  3. 过滤器检查文档的组织标签(比如”技术部”)
  4. 如果用户的组织标签和文档的组织标签匹配,允许访问
  5. 如果不匹配,检查文档是否是”公开”的
  6. 如果不是公开的,返回 403 Forbidden

六、部署方案

6.1 Kubernetes(K8s)部署

什么是 K8s?

  • K8s 是一个容器编排平台(用来管理 Docker 容器)
  • 好处:
    1. 自动扩容:如果流量大了,自动增加 Pod(容器)数量
    2. 自动恢复:如果某个 Pod 挂了,自动重启
    3. 负载均衡:把请求分发到多个 Pod

KnowFlow 的 K8s 部署

  • Deployment:定义应用的副本数量(比如 3 个副本)
  • Service:定义如何访问应用(比如 LoadBalancer)
  • Ingress:定义路由规则(比如 api.example.com 转发到后端服务)

6.2 Prometheus 监控

什么是 Prometheus?

  • Prometheus 是一个监控系统和时序数据库
  • 用来收集应用的指标(比如 QPS、响应时间、错误率)

KnowFlow 的监控指标

  • 文件上传计数器file_upload_counter(记录上传文件的数量)
  • 搜索耗时search_timer(记录搜索的耗时)
  • JVM 指标:内存使用、GC 次数

Prometheus 配置

1
2
3
4
5
scrape_configs:
- job_name: 'knowflow'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['localhost:8080']

七、❗❗ 源码里的问题

问题 1:JWT secret 硬编码在代码里!

看代码(假设在 JwtAuthenticationFilter.java 里)

1
private static final String SECRET = "my-secret-key";  // ❗❗ 硬编码!

问题

  • JWT secret 是用来签名 JWT 的(如果 secret 泄露,攻击者可以伪造 JWT)
  • 硬编码在代码里,容易被反编译(如果代码开源,secret 就泄露了)

修复方案:用环境变量

1
2
@Value("${jwt.secret}")
private String secret; // 从环境变量读取

更好的方案:用 K8s 的 Secret

1
2
3
4
5
6
7
8
# k8s-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: jwt-secret
type: Opaque
data:
jwt-secret: base64-encoded-secret

问题 2:JWT 没有设置过期时间,或者过期时间太长!

看代码(假设在 JwtTokenUtil.java 里)

1
2
3
4
5
6
7
public String generateToken(UserDetails userDetails) {
return Jwts.builder()
.setSubject(userDetails.getUsername())
.setExpiration(new Date(System.currentTimeMillis() + 365 * 24 * 60 * 60 * 1000)) // ❗❗ 365 天!
.signWith(SignatureAlgorithm.HS256, secret)
.compact();
}

问题

  • JWT 过期时间太长(365 天),如果 token 泄露,攻击者可以长期使用
  • 没有刷新 token 机制(用户需要重新登录)

修复方案:设置合理的过期时间 + 刷新 token

1
2
3
4
5
6
7
8
9
10
11
12
13
public String generateToken(UserDetails userDetails) {
return Jwts.builder()
.setSubject(userDetails.getUsername())
.setExpiration(new Date(System.currentTimeMillis() + 1 * 60 * 60 * 1000)) // 1 小时
.signWith(SignatureAlgorithm.HS256, secret)
.compact();
}

// 刷新 token
public String refreshToken(String oldToken) {
String username = extractUsername(oldToken);
return generateToken(username);
}

问题 3:敏感接口没有限流,容易被攻击!

看代码(第 55-57 行)

1
.requestMatchers("/api/v1/users/register", "/api/v1/users/login").permitAll()

问题

  • 登录注册接口没有限流(攻击者可以暴力破解密码)
  • 没有验证码(容易被自动化脚本攻击)

修复方案:加限流

1
2
3
4
5
6
7
8
9
// 用 Redis + Lua 脚本实现限流
public boolean isAllowed(String ip) {
String key = "rate_limit:" + ip;
Long count = redisTemplate.opsForValue().increment(key);
if (count == 1) {
redisTemplate.expire(key, 1, TimeUnit.MINUTES); // 1 分钟内
}
return count <= 100; // 最多 100 次/分钟
}

八、面试八股文

8.1 什么是 JWT?为什么要用 JWT?

  • JWT 是一个”通行证”(包含用户信息的 token)
  • 好处:
    1. 无状态:服务器不需要存 session(适合分布式系统)
    2. 跨域:可以在多个服务之间传递用户信息
    3. 移动端友好:移动端不喜欢用 cookie(JWT 可以用 Header 传递)

8.2 什么是 RBAC?为什么要用 RBAC?

  • RBAC 是基于角色的访问控制
  • 好处:
    1. 灵活性:用户可以分配多个角色
    2. 可维护性:权限变更只需要改角色,不需要改用户
    3. 安全性:最小权限原则(用户只有需要的权限)

8.3 什么是 K8s?为什么要用 K8s?

  • K8s 是一个容器编排平台
  • 好处:
    1. 自动扩容:流量大了自动增加 Pod
    2. 自动恢复:Pod 挂了自动重启
    3. 负载均衡:把请求分发到多个 Pod

8.4 什么是 Prometheus?为什么要用 Prometheus?

  • Prometheus 是一个监控系统和时序数据库
  • 好处:
    1. 实时监控:可以实时查看应用的指标
    2. 告警:指标异常时自动告警
    3. 可视化:配合 Grafana 可以画图表

九、总结

KnowFlow 的安全机制

  1. JWT 认证:无状态的认证方式(适合分布式系统)
  2. RBAC 权限控制:基于角色的访问控制(灵活、可维护)
  3. 组织标签授权:基于组织标签的权限控制(适合企业场景)

KnowFlow 的部署方案

  1. K8s:容器编排(自动扩容、自动恢复)
  2. Prometheus:监控(实时监控、告警)

源码里的问题(❗❗)

  1. JWT secret 硬编码在代码里
  2. JWT 没有设置过期时间,或者过期时间太长
  3. 敏感接口没有限流,容易被攻击

修复方案

  1. 用环境变量或 K8s Secret 存储 JWT secret
  2. 设置合理的过期时间(1 小时)+ 刷新 token 机制
  3. 加限流(Redis + Lua 脚本)

参考资料


最后更新:2026-06-08 22:15:00


KnowFlow 项目学习笔记(三):安全 + 部署深度解析
https://whyalwaysme.lol/2026/06/08/2026-06-08-knowflow-security-deployment-learn/
作者
Cassiur
发布于
2026年6月8日
许可协议