ai-engineering-init 1.7.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/hooks/skill-forced-eval.js +46 -62
- package/.claude/settings.json +10 -1
- package/.claude/skills/api-development/SKILL.md +179 -130
- package/.claude/skills/architecture-design/SKILL.md +102 -212
- package/.claude/skills/backend-annotations/SKILL.md +166 -220
- package/.claude/skills/bug-detective/SKILL.md +225 -186
- package/.claude/skills/code-patterns/SKILL.md +127 -244
- package/.claude/skills/collaborating-with-codex/SKILL.md +96 -113
- package/.claude/skills/crud-development/SKILL.md +226 -307
- package/.claude/skills/data-permission/SKILL.md +131 -202
- package/.claude/skills/database-ops/SKILL.md +158 -355
- package/.claude/skills/error-handler/SKILL.md +224 -285
- package/.claude/skills/file-oss-management/SKILL.md +174 -169
- package/.claude/skills/git-workflow/SKILL.md +123 -341
- package/.claude/skills/json-serialization/SKILL.md +121 -137
- package/.claude/skills/performance-doctor/SKILL.md +83 -89
- package/.claude/skills/redis-cache/SKILL.md +134 -185
- package/.claude/skills/scheduled-jobs/SKILL.md +187 -224
- package/.claude/skills/security-guard/SKILL.md +168 -276
- package/.claude/skills/sms-mail/SKILL.md +266 -228
- package/.claude/skills/social-login/SKILL.md +257 -195
- package/.claude/skills/tenant-management/SKILL.md +172 -188
- package/.claude/skills/utils-toolkit/SKILL.md +214 -222
- package/.claude/skills/websocket-sse/SKILL.md +251 -172
- package/.claude/skills/workflow-engine/SKILL.md +178 -250
- package/.codex/skills/api-development/SKILL.md +179 -130
- package/.codex/skills/architecture-design/SKILL.md +102 -212
- package/.codex/skills/backend-annotations/SKILL.md +166 -220
- package/.codex/skills/bug-detective/SKILL.md +225 -186
- package/.codex/skills/code-patterns/SKILL.md +127 -244
- package/.codex/skills/collaborating-with-codex/SKILL.md +96 -113
- package/.codex/skills/crud-development/SKILL.md +226 -307
- package/.codex/skills/data-permission/SKILL.md +131 -202
- package/.codex/skills/database-ops/SKILL.md +158 -355
- package/.codex/skills/error-handler/SKILL.md +224 -285
- package/.codex/skills/file-oss-management/SKILL.md +174 -169
- package/.codex/skills/git-workflow/SKILL.md +123 -341
- package/.codex/skills/json-serialization/SKILL.md +121 -137
- package/.codex/skills/performance-doctor/SKILL.md +83 -89
- package/.codex/skills/redis-cache/SKILL.md +134 -185
- package/.codex/skills/scheduled-jobs/SKILL.md +187 -224
- package/.codex/skills/security-guard/SKILL.md +168 -276
- package/.codex/skills/sms-mail/SKILL.md +266 -228
- package/.codex/skills/social-login/SKILL.md +257 -195
- package/.codex/skills/tenant-management/SKILL.md +172 -188
- package/.codex/skills/utils-toolkit/SKILL.md +214 -222
- package/.codex/skills/websocket-sse/SKILL.md +251 -172
- package/.codex/skills/workflow-engine/SKILL.md +178 -250
- package/.cursor/hooks/cursor-skill-eval.js +66 -6
- package/.cursor/skills/api-development/SKILL.md +179 -130
- package/.cursor/skills/architecture-design/SKILL.md +102 -212
- package/.cursor/skills/backend-annotations/SKILL.md +166 -220
- package/.cursor/skills/bug-detective/SKILL.md +225 -186
- package/.cursor/skills/code-patterns/SKILL.md +127 -244
- package/.cursor/skills/collaborating-with-codex/SKILL.md +96 -113
- package/.cursor/skills/crud-development/SKILL.md +226 -307
- package/.cursor/skills/data-permission/SKILL.md +131 -202
- package/.cursor/skills/database-ops/SKILL.md +158 -355
- package/.cursor/skills/error-handler/SKILL.md +224 -285
- package/.cursor/skills/file-oss-management/SKILL.md +174 -169
- package/.cursor/skills/git-workflow/SKILL.md +123 -341
- package/.cursor/skills/json-serialization/SKILL.md +121 -137
- package/.cursor/skills/performance-doctor/SKILL.md +83 -89
- package/.cursor/skills/redis-cache/SKILL.md +134 -185
- package/.cursor/skills/scheduled-jobs/SKILL.md +187 -224
- package/.cursor/skills/security-guard/SKILL.md +168 -276
- package/.cursor/skills/sms-mail/SKILL.md +266 -228
- package/.cursor/skills/social-login/SKILL.md +257 -195
- package/.cursor/skills/tenant-management/SKILL.md +172 -188
- package/.cursor/skills/utils-toolkit/SKILL.md +214 -222
- package/.cursor/skills/websocket-sse/SKILL.md +251 -172
- package/.cursor/skills/workflow-engine/SKILL.md +178 -250
- package/AGENTS.md +49 -540
- package/CLAUDE.md +73 -119
- package/README.md +37 -6
- package/bin/index.js +5 -1
- package/package.json +1 -1
- package/src/skills/api-development/SKILL.md +179 -130
- package/src/skills/architecture-design/SKILL.md +102 -212
- package/src/skills/backend-annotations/SKILL.md +166 -220
- package/src/skills/bug-detective/SKILL.md +225 -186
- package/src/skills/code-patterns/SKILL.md +127 -244
- package/src/skills/collaborating-with-codex/SKILL.md +96 -113
- package/src/skills/crud-development/SKILL.md +226 -307
- package/src/skills/data-permission/SKILL.md +131 -202
- package/src/skills/database-ops/SKILL.md +158 -355
- package/src/skills/error-handler/SKILL.md +224 -285
- package/src/skills/file-oss-management/SKILL.md +174 -169
- package/src/skills/git-workflow/SKILL.md +123 -341
- package/src/skills/json-serialization/SKILL.md +121 -137
- package/src/skills/performance-doctor/SKILL.md +83 -89
- package/src/skills/redis-cache/SKILL.md +134 -185
- package/src/skills/scheduled-jobs/SKILL.md +187 -224
- package/src/skills/security-guard/SKILL.md +168 -276
- package/src/skills/sms-mail/SKILL.md +266 -228
- package/src/skills/social-login/SKILL.md +257 -195
- package/src/skills/tenant-management/SKILL.md +172 -188
- package/src/skills/utils-toolkit/SKILL.md +214 -222
- package/src/skills/websocket-sse/SKILL.md +251 -172
- package/src/skills/workflow-engine/SKILL.md +178 -250
- package/.claude/skills/skill-creator/LICENSE.txt +0 -202
- package/.claude/skills/skill-creator/SKILL.md +0 -479
- package/.claude/skills/skill-creator/agents/analyzer.md +0 -274
- package/.claude/skills/skill-creator/agents/comparator.md +0 -202
- package/.claude/skills/skill-creator/agents/grader.md +0 -223
- package/.claude/skills/skill-creator/assets/eval_review.html +0 -146
- package/.claude/skills/skill-creator/eval-viewer/generate_review.py +0 -471
- package/.claude/skills/skill-creator/eval-viewer/viewer.html +0 -1325
- package/.claude/skills/skill-creator/references/schemas.md +0 -430
- package/.claude/skills/skill-creator/scripts/__init__.py +0 -0
- package/.claude/skills/skill-creator/scripts/aggregate_benchmark.py +0 -401
- package/.claude/skills/skill-creator/scripts/generate_report.py +0 -326
- package/.claude/skills/skill-creator/scripts/improve_description.py +0 -248
- package/.claude/skills/skill-creator/scripts/package_skill.py +0 -136
- package/.claude/skills/skill-creator/scripts/quick_validate.py +0 -103
- package/.claude/skills/skill-creator/scripts/run_eval.py +0 -310
- package/.claude/skills/skill-creator/scripts/run_loop.py +0 -332
- package/.claude/skills/skill-creator/scripts/utils.py +0 -47
|
@@ -1,302 +1,248 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: backend-annotations
|
|
3
3
|
description: |
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
通用后端高级注解指南。包含限流、防重复提交、数据脱敏、字段加密、接口加密等横切关注点的 AOP 实现模式。
|
|
6
5
|
触发场景:
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
触发词:注解、@RateLimiter、@RepeatSubmit、@Sensitive、@EncryptField、@ApiEncrypt、@DataPermission、@DataColumn、限流、防重复、脱敏、加密、数据权限注解
|
|
6
|
+
- 配置接口限流
|
|
7
|
+
- 配置防重复提交
|
|
8
|
+
- 配置数据脱敏
|
|
9
|
+
- 配置字段加密 / 接口加密
|
|
10
|
+
触发词:注解、限流、防重复提交、脱敏、加密、RateLimiter、Idempotent、Sensitive、Encrypt、AOP
|
|
11
|
+
注意:如果项目有专属技能(如 `leniu-backend-annotations`),优先使用专属版本。
|
|
15
12
|
---
|
|
16
13
|
|
|
17
|
-
#
|
|
14
|
+
# 后端高级注解开发指南
|
|
18
15
|
|
|
19
|
-
>
|
|
16
|
+
> 通用模板。如果项目有专属技能(如 `leniu-backend-annotations`),优先使用。
|
|
20
17
|
|
|
21
|
-
##
|
|
18
|
+
## 设计原则
|
|
22
19
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
| `@Sensitive` | Jackson 序列化器 | VO 字段 | 无 |
|
|
28
|
-
| `@EncryptField` | MyBatis 拦截器 | Entity 字段 | 无 |
|
|
29
|
-
| `@ApiEncrypt` | 拦截器 | Controller 方法 | 无 |
|
|
30
|
-
| `@DataPermission` | AOP | Mapper 接口 | MyBatis |
|
|
20
|
+
1. **横切关注点用 AOP**:限流、防重复、脱敏、加密属于非功能性需求,应通过注解 + AOP/拦截器实现,不侵入业务代码。
|
|
21
|
+
2. **分层职责清晰**:限流/防重复作用于 Controller 层;脱敏作用于 VO 序列化层;加密作用于持久化层。
|
|
22
|
+
3. **声明式优于编程式**:用注解声明意图,框架自动执行,减少样板代码。
|
|
23
|
+
4. **配置外置**:密钥、阈值等参数放在配置文件或配置中心,不硬编码。
|
|
31
24
|
|
|
32
25
|
---
|
|
33
26
|
|
|
34
|
-
##
|
|
27
|
+
## 实现模式
|
|
35
28
|
|
|
36
|
-
|
|
29
|
+
### 1. 接口限流
|
|
37
30
|
|
|
38
|
-
|
|
39
|
-
|------|------|--------|------|
|
|
40
|
-
| `key` | String | "" | 限流key,支持SpEL |
|
|
41
|
-
| `time` | int | 60 | 时间窗口(秒) |
|
|
42
|
-
| `count` | int | 100 | 最大请求次数 |
|
|
43
|
-
| `limitType` | LimitType | DEFAULT | DEFAULT/IP/CLUSTER |
|
|
44
|
-
| `message` | String | 国际化key | 错误提示 |
|
|
31
|
+
**概念**:通过 AOP 拦截请求,基于 Redis/内存计数器控制单位时间内的请求次数。
|
|
45
32
|
|
|
46
33
|
```java
|
|
47
|
-
//
|
|
48
|
-
@
|
|
49
|
-
@
|
|
50
|
-
public
|
|
51
|
-
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
@
|
|
60
|
-
|
|
34
|
+
// 自定义注解
|
|
35
|
+
@Target(ElementType.METHOD)
|
|
36
|
+
@Retention(RetentionPolicy.RUNTIME)
|
|
37
|
+
public @interface RateLimiter {
|
|
38
|
+
String key() default ""; // 限流key,支持 SpEL
|
|
39
|
+
int time() default 60; // 时间窗口(秒)
|
|
40
|
+
int count() default 100; // 最大请求次数
|
|
41
|
+
LimitType limitType() default LimitType.DEFAULT; // DEFAULT / IP / CLUSTER
|
|
42
|
+
String message() default "请求过于频繁";
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// AOP 切面
|
|
46
|
+
@Aspect
|
|
47
|
+
@Component
|
|
48
|
+
public class RateLimiterAspect {
|
|
49
|
+
|
|
50
|
+
@Autowired
|
|
51
|
+
private StringRedisTemplate redisTemplate;
|
|
52
|
+
|
|
53
|
+
@Around("@annotation([你的包名].annotation.RateLimiter)")
|
|
54
|
+
public Object around(ProceedingJoinPoint point) throws Throwable {
|
|
55
|
+
RateLimiter limiter = /* 获取注解 */;
|
|
56
|
+
String key = buildKey(limiter, point);
|
|
57
|
+
// 使用 Redis Lua 脚本做原子计数
|
|
58
|
+
Long count = redisTemplate.execute(rateLimiterScript, List.of(key),
|
|
59
|
+
String.valueOf(limiter.count()), String.valueOf(limiter.time()));
|
|
60
|
+
if (count != null && count > limiter.count()) {
|
|
61
|
+
throw new [你的异常类](limiter.message());
|
|
62
|
+
}
|
|
63
|
+
return point.proceed();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
61
66
|
```
|
|
62
67
|
|
|
63
|
-
|
|
68
|
+
**推荐阈值参考**:
|
|
64
69
|
|
|
65
|
-
|
|
70
|
+
| 场景 | 时间窗口 | 次数 | 限流类型 |
|
|
71
|
+
|------|---------|------|---------|
|
|
72
|
+
| 登录接口 | 60s | 5-10 | IP |
|
|
73
|
+
| 验证码 | 60s | 3 | IP |
|
|
74
|
+
| 查询接口 | 60s | 100-1000 | DEFAULT |
|
|
75
|
+
| 写入接口 | 60s | 10-50 | DEFAULT |
|
|
76
|
+
| 敏感操作 | 60s | 1-5 | IP |
|
|
77
|
+
|
|
78
|
+
---
|
|
66
79
|
|
|
67
|
-
|
|
80
|
+
### 2. 防重复提交
|
|
68
81
|
|
|
69
|
-
|
|
70
|
-
|------|------|--------|------|
|
|
71
|
-
| `interval` | int | 5000 | 间隔时间(毫秒) |
|
|
72
|
-
| `timeUnit` | TimeUnit | MILLISECONDS | 时间单位 |
|
|
73
|
-
| `message` | String | 国际化key | 错误提示 |
|
|
82
|
+
**概念**:在指定时间窗口内,相同用户的相同请求(基于 Token + 参数哈希)只允许提交一次。
|
|
74
83
|
|
|
75
84
|
```java
|
|
76
|
-
|
|
77
|
-
@
|
|
78
|
-
@
|
|
79
|
-
|
|
85
|
+
@Target(ElementType.METHOD)
|
|
86
|
+
@Retention(RetentionPolicy.RUNTIME)
|
|
87
|
+
public @interface RepeatSubmit {
|
|
88
|
+
int interval() default 5000; // 间隔时间(毫秒)
|
|
89
|
+
TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
|
|
90
|
+
String message() default "请勿重复提交";
|
|
91
|
+
}
|
|
80
92
|
|
|
81
|
-
//
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
93
|
+
// AOP 切面核心逻辑
|
|
94
|
+
// 1. 从请求中提取 Token + 请求参数
|
|
95
|
+
// 2. 计算 MD5(token + ":" + serialize(params))
|
|
96
|
+
// 3. Redis SETNX,设置过期时间 = interval
|
|
97
|
+
// 4. 设置成功 -> 允许请求;设置失败 -> 拒绝
|
|
98
|
+
// 5. 请求异常时删除 key,允许重试
|
|
85
99
|
```
|
|
86
100
|
|
|
87
|
-
|
|
101
|
+
| 场景 | 推荐间隔 |
|
|
102
|
+
|------|---------|
|
|
103
|
+
| 普通表单 | 3-5 秒 |
|
|
104
|
+
| 订单创建 | 10 秒 |
|
|
105
|
+
| 支付操作 | 30 秒 |
|
|
106
|
+
| 文件上传 | 10 秒 |
|
|
88
107
|
|
|
89
108
|
---
|
|
90
109
|
|
|
91
|
-
|
|
110
|
+
### 3. 数据脱敏
|
|
92
111
|
|
|
93
|
-
|
|
112
|
+
**概念**:在 JSON 序列化阶段,对 VO 中的敏感字段进行掩码处理。通过自定义 Jackson 序列化器实现。
|
|
94
113
|
|
|
95
|
-
|
|
114
|
+
```java
|
|
115
|
+
@Target(ElementType.FIELD)
|
|
116
|
+
@Retention(RetentionPolicy.RUNTIME)
|
|
117
|
+
@JacksonAnnotationsInside
|
|
118
|
+
@JsonSerialize(using = SensitiveSerializer.class)
|
|
119
|
+
public @interface Sensitive {
|
|
120
|
+
SensitiveStrategy strategy();
|
|
121
|
+
String[] roleKey() default {}; // 拥有这些角色可查看原文
|
|
122
|
+
String[] perms() default {}; // 拥有这些权限可查看原文
|
|
123
|
+
}
|
|
96
124
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
125
|
+
public enum SensitiveStrategy {
|
|
126
|
+
ID_CARD(s -> s.substring(0, 3) + "***" + s.substring(s.length() - 4)),
|
|
127
|
+
PHONE(s -> s.substring(0, 3) + "****" + s.substring(s.length() - 4)),
|
|
128
|
+
EMAIL(s -> s.charAt(0) + "**@" + s.substring(s.indexOf('@') + 1)),
|
|
129
|
+
CHINESE_NAME(s -> s.charAt(0) + "*".repeat(s.length() - 1)),
|
|
130
|
+
BANK_CARD(s -> s.substring(0, 4) + "****" + s.substring(s.length() - 4)),
|
|
131
|
+
PASSWORD(s -> "******");
|
|
104
132
|
|
|
105
|
-
|
|
133
|
+
private final Function<String, String> desensitizer;
|
|
134
|
+
// constructor, getter...
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// 使用
|
|
106
138
|
public class UserVo {
|
|
107
|
-
// 所有人看脱敏数据
|
|
108
139
|
@Sensitive(strategy = SensitiveStrategy.PHONE)
|
|
109
140
|
private String phone;
|
|
110
141
|
|
|
111
|
-
// admin 角色可查看原数据
|
|
112
142
|
@Sensitive(strategy = SensitiveStrategy.ID_CARD, roleKey = {"admin"})
|
|
113
143
|
private String idCard;
|
|
114
|
-
|
|
115
|
-
// 需要权限才能看原数据
|
|
116
|
-
@Sensitive(strategy = SensitiveStrategy.EMAIL, perms = {"system:user:detail"})
|
|
117
|
-
private String email;
|
|
118
144
|
}
|
|
119
145
|
```
|
|
120
146
|
|
|
121
|
-
**权限逻辑**:roleKey 和 perms 都为空 =
|
|
147
|
+
**权限逻辑**:roleKey 和 perms 都为空 = 全部脱敏;满足任一条件 = 可查看原文(OR 关系)。
|
|
122
148
|
|
|
123
149
|
---
|
|
124
150
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
**导入**:`org.dromara.common.encrypt.annotation.EncryptField`
|
|
151
|
+
### 4. 字段加密(持久层)
|
|
128
152
|
|
|
129
|
-
|
|
130
|
-
|------|------|------|------|
|
|
131
|
-
| `BASE64` | 编码(低安全) | `AES` | 对称加密(推荐) |
|
|
132
|
-
| `RSA` | 非对称(高安全) | `SM2` | 国密非对称 |
|
|
133
|
-
| `SM4` | 国密对称 | | |
|
|
153
|
+
**概念**:通过 MyBatis 拦截器/TypeHandler,在数据写入数据库时自动加密,读取时自动解密。对业务代码透明。
|
|
134
154
|
|
|
135
155
|
```java
|
|
136
|
-
@
|
|
137
|
-
@
|
|
138
|
-
public
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
// RSA 加密(指定公私钥)
|
|
144
|
-
@EncryptField(algorithm = AlgorithmType.RSA,
|
|
145
|
-
privateKey = "MIICdQ...", publicKey = "MFkwEw...")
|
|
146
|
-
private String idCard;
|
|
147
|
-
|
|
148
|
-
// 使用 yml 默认配置
|
|
149
|
-
@EncryptField
|
|
150
|
-
private String secretField;
|
|
156
|
+
@Target(ElementType.FIELD)
|
|
157
|
+
@Retention(RetentionPolicy.RUNTIME)
|
|
158
|
+
public @interface EncryptField {
|
|
159
|
+
AlgorithmType algorithm() default AlgorithmType.DEFAULT; // 使用全局配置
|
|
160
|
+
String password() default ""; // AES/SM4 密钥
|
|
161
|
+
String publicKey() default ""; // RSA/SM2 公钥
|
|
162
|
+
String privateKey() default ""; // RSA/SM2 私钥
|
|
151
163
|
}
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
**配置**:
|
|
155
|
-
|
|
156
|
-
```yaml
|
|
157
|
-
mybatis-encryptor:
|
|
158
|
-
enable: false
|
|
159
|
-
algorithm: BASE64 # 默认算法
|
|
160
|
-
encode: BASE64 # 编码方式:BASE64 | HEX
|
|
161
|
-
password: your-secret-16 # AES/SM4 秘钥(16字符)
|
|
162
|
-
publicKey: MFwwDQ... # RSA/SM2 公钥
|
|
163
|
-
privateKey: MIIBVAIBADANBg... # RSA/SM2 私钥
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
---
|
|
167
|
-
|
|
168
|
-
## 5. @ApiEncrypt - 接口加密
|
|
169
164
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
// 加密响应数据
|
|
174
|
-
@ApiEncrypt(response = true)
|
|
175
|
-
@GetMapping("/{id}")
|
|
176
|
-
public R<UserVo> getUser(@PathVariable Long id) { }
|
|
165
|
+
public enum AlgorithmType {
|
|
166
|
+
DEFAULT, BASE64, AES, RSA, SM2, SM4
|
|
167
|
+
}
|
|
177
168
|
```
|
|
178
169
|
|
|
179
|
-
|
|
180
|
-
|------|------|--------|------|
|
|
181
|
-
| `response` | boolean | false | 是否加密响应 |
|
|
182
|
-
|
|
183
|
-
**配置**:
|
|
170
|
+
**配置示例**:
|
|
184
171
|
|
|
185
172
|
```yaml
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
173
|
+
# [你的加密配置前缀]:
|
|
174
|
+
encrypt:
|
|
175
|
+
enable: true
|
|
176
|
+
algorithm: AES
|
|
177
|
+
password: your-secret-key-16ch # AES/SM4 密钥(16字符)
|
|
178
|
+
public-key: MFkwEw... # RSA/SM2 公钥
|
|
179
|
+
private-key: MIIBVAIBADANBg... # RSA/SM2 私钥
|
|
191
180
|
```
|
|
192
181
|
|
|
193
182
|
---
|
|
194
183
|
|
|
195
|
-
|
|
184
|
+
### 5. 接口加密(传输层)
|
|
196
185
|
|
|
197
|
-
|
|
186
|
+
**概念**:通过 Filter/Interceptor,对 HTTP 请求体自动解密、响应体自动加密。适用于前后端通信加密。
|
|
198
187
|
|
|
199
188
|
```java
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
@DataColumn(key = "deptName", value = "dept_id"),
|
|
205
|
-
@DataColumn(key = "userName", value = "create_by")
|
|
206
|
-
})
|
|
207
|
-
default Page<OrderVo> selectPageOrderList(Page<Order> page, Wrapper<Order> wrapper) {
|
|
208
|
-
return this.selectVoPage(page, wrapper);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// 使用表别名
|
|
212
|
-
@DataPermission({
|
|
213
|
-
@DataColumn(key = "deptName", value = "d.dept_id"),
|
|
214
|
-
@DataColumn(key = "userName", value = "u.create_by")
|
|
215
|
-
})
|
|
216
|
-
List<OrderVo> selectWithJoin(@Param(Constants.WRAPPER) Wrapper<Order> wrapper);
|
|
189
|
+
@Target(ElementType.METHOD)
|
|
190
|
+
@Retention(RetentionPolicy.RUNTIME)
|
|
191
|
+
public @interface ApiEncrypt {
|
|
192
|
+
boolean response() default false; // 是否加密响应
|
|
217
193
|
}
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
**@DataColumn 参数**:
|
|
221
194
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
| `value` | "dept_id" | 替换的字段名 |
|
|
226
|
-
| `permission` | "" | 拥有此权限则不过滤 |
|
|
227
|
-
|
|
228
|
-
**权限范围**:全部数据 / 本部门 / 本部门及以下 / 仅本人 / 自定义。
|
|
195
|
+
// 在 RequestBodyAdvice / ResponseBodyAdvice 中拦截处理
|
|
196
|
+
// 或通过 Filter + HttpServletRequestWrapper 实现
|
|
197
|
+
```
|
|
229
198
|
|
|
230
199
|
---
|
|
231
200
|
|
|
232
|
-
##
|
|
201
|
+
## 选型建议
|
|
233
202
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
```
|
|
203
|
+
| 关注点 | 实现方式 | 作用层 | 依赖 |
|
|
204
|
+
|--------|---------|--------|------|
|
|
205
|
+
| 限流 | AOP + Redis Lua 脚本 | Controller | Redis |
|
|
206
|
+
| 防重复 | AOP + Redis SETNX | Controller | Redis + Token |
|
|
207
|
+
| 脱敏 | Jackson 自定义序列化器 | VO 字段 | 无 |
|
|
208
|
+
| 字段加密 | MyBatis 拦截器 / TypeHandler | Entity 字段 | 加密库 |
|
|
209
|
+
| 接口加密 | Filter / RequestBodyAdvice | Controller 方法 | 加密库 |
|
|
242
210
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
public class UserVo {
|
|
252
|
-
@Sensitive(strategy = SensitiveStrategy.PHONE)
|
|
253
|
-
private String phone; // 序列化时脱敏
|
|
254
|
-
}
|
|
255
|
-
```
|
|
211
|
+
| 加密算法 | 类型 | 密钥要求 | 适用场景 |
|
|
212
|
+
|---------|------|---------|---------|
|
|
213
|
+
| BASE64 | 编码(非加密) | 无 | 简单混淆 |
|
|
214
|
+
| AES | 对称加密 | 16/24/32 字节 | 通用加密(推荐) |
|
|
215
|
+
| RSA | 非对称加密 | 公钥/私钥对 | 高安全场景 |
|
|
216
|
+
| SM4 | 国密对称 | 16 字节 | 国密合规 |
|
|
217
|
+
| SM2 | 国密非对称 | 公钥/私钥对 | 国密合规 |
|
|
256
218
|
|
|
257
219
|
---
|
|
258
220
|
|
|
259
|
-
##
|
|
221
|
+
## 常见错误
|
|
260
222
|
|
|
261
223
|
```java
|
|
262
|
-
//
|
|
224
|
+
// 1. 限流/防重复注解放在 Service 方法上(无效,应在 Controller)
|
|
263
225
|
@Service
|
|
264
226
|
public class XxxService {
|
|
265
|
-
@RateLimiter(...) // 无效!
|
|
227
|
+
@RateLimiter(...) // 无效!AOP 通常只拦截 Controller
|
|
266
228
|
public void doSomething() { }
|
|
267
229
|
}
|
|
268
230
|
|
|
269
|
-
//
|
|
270
|
-
|
|
271
|
-
public interface UserMapper { }
|
|
272
|
-
|
|
273
|
-
// ❌ @Sensitive 用在 Entity 上(应在 VO 上)
|
|
274
|
-
// ❌ @EncryptField 用在 VO 上(应在 Entity 上)
|
|
275
|
-
|
|
276
|
-
// ✅ @DataPermission 支持类级别 + 方法级别(方法覆盖类)
|
|
277
|
-
@DataPermission({ @DataColumn(key = "deptName", value = "dept_id") })
|
|
278
|
-
public interface UserMapper {
|
|
279
|
-
@DataPermission({ /* 方法级覆盖 */ })
|
|
280
|
-
List<UserVo> selectList();
|
|
281
|
-
}
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
---
|
|
231
|
+
// 2. @Sensitive 用在 Entity 上(应在 VO 上,序列化时生效)
|
|
232
|
+
// 3. @EncryptField 用在 VO 上(应在 Entity 上,持久化时生效)
|
|
285
233
|
|
|
286
|
-
|
|
234
|
+
// 4. 加密密钥硬编码在注解中
|
|
235
|
+
@EncryptField(password = "my-secret-key") // 不安全
|
|
236
|
+
// 应使用全局配置或环境变量
|
|
287
237
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
| 脱敏示例 | `org.dromara.demo.controller.TestSensitiveController` |
|
|
292
|
-
| 加密示例 | `org.dromara.demo.domain.TestDemo` |
|
|
293
|
-
| 数据权限 | `org.dromara.system.mapper.SysUserMapper` |
|
|
238
|
+
// 5. 限流 key 设计不合理
|
|
239
|
+
@RateLimiter(key = "") // 所有用户共享限流
|
|
240
|
+
// 应根据场景选择:用户维度 key="#userId",IP 维度 limitType=IP
|
|
294
241
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
spring.data.redis.* → @RateLimiter/@RepeatSubmit 依赖
|
|
242
|
+
// 6. 组合注解顺序不当
|
|
243
|
+
// 推荐顺序:限流 -> 防重复 -> 权限 -> 日志
|
|
244
|
+
@RateLimiter(time = 60, count = 10)
|
|
245
|
+
@RepeatSubmit(interval = 5000)
|
|
246
|
+
@PostMapping()
|
|
247
|
+
public Result<?> add(@RequestBody XxxDTO dto) { }
|
|
302
248
|
```
|