ai-engineering-init 1.3.4 → 1.4.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.
Files changed (226) hide show
  1. package/.claude/hooks/skill-forced-eval.js +2 -0
  2. package/.claude/settings.json +3 -3
  3. package/.claude/skills/add-skill/SKILL.md +79 -32
  4. package/.claude/skills/api-development/SKILL.md +83 -377
  5. package/.claude/skills/architecture-design/SKILL.md +138 -632
  6. package/.claude/skills/backend-annotations/SKILL.md +134 -506
  7. package/.claude/skills/banana-image/SKILL.md +10 -3
  8. package/.claude/skills/brainstorm/SKILL.md +103 -535
  9. package/.claude/skills/bug-detective/SKILL.md +147 -1097
  10. package/.claude/skills/bug-detective/references/error-patterns.md +242 -0
  11. package/.claude/skills/code-patterns/SKILL.md +116 -426
  12. package/.claude/skills/code-patterns/references/leniu-code-patterns.md +87 -0
  13. package/.claude/skills/crud-development/SKILL.md +64 -304
  14. package/.claude/skills/data-permission/SKILL.md +105 -412
  15. package/.claude/skills/data-permission/references/custom-data-scope.md +90 -0
  16. package/.claude/skills/file-oss-management/SKILL.md +106 -714
  17. package/.claude/skills/file-oss-management/references/entities.md +105 -0
  18. package/.claude/skills/file-oss-management/references/service-impl.md +104 -0
  19. package/.claude/skills/leniu-api-development/SKILL.md +142 -626
  20. package/.claude/skills/leniu-api-development/references/real-examples.md +273 -0
  21. package/.claude/skills/leniu-architecture-design/SKILL.md +176 -391
  22. package/.claude/skills/leniu-backend-annotations/SKILL.md +132 -519
  23. package/.claude/skills/leniu-brainstorm/SKILL.md +132 -541
  24. package/.claude/skills/leniu-brainstorm/references/business-scenarios.md +162 -0
  25. package/.claude/skills/leniu-crud-development/SKILL.md +232 -938
  26. package/.claude/skills/leniu-crud-development/references/templates.md +597 -0
  27. package/.claude/skills/leniu-customization-location/SKILL.md +410 -0
  28. package/.claude/skills/leniu-data-permission/SKILL.md +70 -0
  29. package/.claude/skills/leniu-java-entity/SKILL.md +76 -590
  30. package/.claude/skills/leniu-java-entity/references/templates.md +237 -0
  31. package/.claude/skills/leniu-java-export/SKILL.md +94 -379
  32. package/.claude/skills/leniu-java-logging/SKILL.md +106 -709
  33. package/.claude/skills/leniu-java-logging/references/data-mask.md +46 -0
  34. package/.claude/skills/leniu-java-logging/references/logging-scenarios.md +113 -0
  35. package/.claude/skills/leniu-java-mybatis/SKILL.md +73 -446
  36. package/.claude/skills/leniu-java-mybatis/references/report-mapper.md +88 -0
  37. package/.claude/skills/leniu-report-customization/SKILL.md +111 -365
  38. package/.claude/skills/leniu-report-customization/references/table-fields.md +93 -0
  39. package/.claude/skills/leniu-report-standard-customization/SKILL.md +111 -334
  40. package/.claude/skills/leniu-report-standard-customization/references/analysis-module.md +64 -0
  41. package/.claude/skills/leniu-report-standard-customization/references/table-fields.md +113 -0
  42. package/.claude/skills/leniu-security-guard/SKILL.md +133 -347
  43. package/.claude/skills/mysql-debug/SKILL.md +364 -0
  44. package/.claude/skills/openspec-apply-change/SKILL.md +10 -1
  45. package/.claude/skills/openspec-archive-change/SKILL.md +9 -1
  46. package/.claude/skills/openspec-bulk-archive-change/SKILL.md +9 -1
  47. package/.claude/skills/openspec-continue-change/SKILL.md +9 -1
  48. package/.claude/skills/openspec-explore/SKILL.md +10 -1
  49. package/.claude/skills/openspec-ff-change/SKILL.md +9 -1
  50. package/.claude/skills/openspec-new-change/SKILL.md +9 -1
  51. package/.claude/skills/openspec-onboard/SKILL.md +15 -130
  52. package/.claude/skills/openspec-sync-specs/SKILL.md +9 -1
  53. package/.claude/skills/openspec-verify-change/SKILL.md +9 -1
  54. package/.claude/skills/performance-doctor/SKILL.md +110 -434
  55. package/.claude/skills/redis-cache/SKILL.md +89 -595
  56. package/.claude/skills/redis-cache/references/listeners.md +23 -0
  57. package/.claude/skills/scheduled-jobs/SKILL.md +88 -407
  58. package/.claude/skills/security-guard/SKILL.md +137 -532
  59. package/.claude/skills/security-guard/references/encrypt-config.md +103 -0
  60. package/.claude/skills/security-guard/references/sensitive-strategies.md +42 -0
  61. package/.claude/skills/sms-mail/SKILL.md +116 -574
  62. package/.claude/skills/sms-mail/references/mail-config.md +88 -0
  63. package/.claude/skills/sms-mail/references/sms-config.md +74 -0
  64. package/.claude/skills/social-login/SKILL.md +112 -514
  65. package/.claude/skills/social-login/references/provider-configs.md +118 -0
  66. package/.claude/skills/tenant-management/SKILL.md +129 -444
  67. package/.claude/skills/tenant-management/references/tenant-scenarios.md +91 -0
  68. package/.claude/skills/test-development/SKILL.md +86 -540
  69. package/.claude/skills/test-development/references/parameterized-examples.md +119 -0
  70. package/.claude/skills/utils-toolkit/SKILL.md +52 -305
  71. package/.claude/skills/utils-toolkit/references/redis-utils-api.md +56 -0
  72. package/.claude/skills/websocket-sse/SKILL.md +105 -550
  73. package/.claude/skills/workflow-engine/SKILL.md +147 -502
  74. package/.codex/skills/add-skill/SKILL.md +79 -32
  75. package/.codex/skills/api-development/SKILL.md +172 -599
  76. package/.codex/skills/architecture-design/SKILL.md +138 -504
  77. package/.codex/skills/backend-annotations/SKILL.md +134 -496
  78. package/.codex/skills/banana-image/SKILL.md +10 -3
  79. package/.codex/skills/brainstorm/SKILL.md +103 -535
  80. package/.codex/skills/bug-detective/SKILL.md +147 -1097
  81. package/.codex/skills/bug-detective/references/error-patterns.md +242 -0
  82. package/.codex/skills/code-patterns/SKILL.md +120 -282
  83. package/.codex/skills/code-patterns/references/leniu-code-patterns.md +87 -0
  84. package/.codex/skills/crud-development/SKILL.md +64 -292
  85. package/.codex/skills/data-permission/SKILL.md +108 -407
  86. package/.codex/skills/data-permission/references/custom-data-scope.md +90 -0
  87. package/.codex/skills/database-ops/SKILL.md +8 -154
  88. package/.codex/skills/error-handler/SKILL.md +10 -0
  89. package/.codex/skills/file-oss-management/SKILL.md +106 -714
  90. package/.codex/skills/file-oss-management/references/entities.md +105 -0
  91. package/.codex/skills/file-oss-management/references/service-impl.md +104 -0
  92. package/.codex/skills/git-workflow/SKILL.md +27 -5
  93. package/.codex/skills/leniu-api-development/SKILL.md +142 -626
  94. package/.codex/skills/leniu-api-development/references/real-examples.md +273 -0
  95. package/.codex/skills/leniu-architecture-design/SKILL.md +176 -391
  96. package/.codex/skills/leniu-backend-annotations/SKILL.md +132 -519
  97. package/.codex/skills/leniu-brainstorm/SKILL.md +132 -541
  98. package/.codex/skills/leniu-brainstorm/references/business-scenarios.md +162 -0
  99. package/.codex/skills/leniu-crud-development/SKILL.md +232 -938
  100. package/.codex/skills/leniu-crud-development/references/templates.md +597 -0
  101. package/.codex/skills/leniu-customization-location/SKILL.md +410 -0
  102. package/.codex/skills/leniu-data-permission/SKILL.md +70 -0
  103. package/.codex/skills/leniu-java-code-style/SKILL.md +510 -0
  104. package/.codex/skills/leniu-java-entity/SKILL.md +76 -590
  105. package/.codex/skills/leniu-java-entity/references/templates.md +237 -0
  106. package/.codex/skills/leniu-java-export/SKILL.md +94 -379
  107. package/.codex/skills/leniu-java-logging/SKILL.md +106 -709
  108. package/.codex/skills/leniu-java-logging/references/data-mask.md +46 -0
  109. package/.codex/skills/leniu-java-logging/references/logging-scenarios.md +113 -0
  110. package/.codex/skills/leniu-java-mybatis/SKILL.md +73 -446
  111. package/.codex/skills/leniu-java-mybatis/references/report-mapper.md +88 -0
  112. package/.codex/skills/leniu-report-customization/SKILL.md +111 -365
  113. package/.codex/skills/leniu-report-customization/references/table-fields.md +93 -0
  114. package/.codex/skills/leniu-report-standard-customization/SKILL.md +111 -334
  115. package/.codex/skills/leniu-report-standard-customization/references/analysis-module.md +64 -0
  116. package/.codex/skills/leniu-report-standard-customization/references/table-fields.md +113 -0
  117. package/.codex/skills/leniu-security-guard/SKILL.md +133 -347
  118. package/.codex/skills/mysql-debug/SKILL.md +364 -0
  119. package/.codex/skills/openspec-apply-change/SKILL.md +10 -1
  120. package/.codex/skills/openspec-archive-change/SKILL.md +9 -1
  121. package/.codex/skills/openspec-bulk-archive-change/SKILL.md +9 -1
  122. package/.codex/skills/openspec-continue-change/SKILL.md +9 -1
  123. package/.codex/skills/openspec-explore/SKILL.md +10 -1
  124. package/.codex/skills/openspec-ff-change/SKILL.md +9 -1
  125. package/.codex/skills/openspec-new-change/SKILL.md +9 -1
  126. package/.codex/skills/openspec-onboard/SKILL.md +15 -130
  127. package/.codex/skills/openspec-sync-specs/SKILL.md +9 -1
  128. package/.codex/skills/openspec-verify-change/SKILL.md +9 -1
  129. package/.codex/skills/performance-doctor/SKILL.md +110 -434
  130. package/.codex/skills/project-navigator/SKILL.md +20 -1
  131. package/.codex/skills/redis-cache/SKILL.md +93 -589
  132. package/.codex/skills/redis-cache/references/listeners.md +23 -0
  133. package/.codex/skills/scheduled-jobs/SKILL.md +88 -407
  134. package/.codex/skills/security-guard/SKILL.md +141 -527
  135. package/.codex/skills/security-guard/references/encrypt-config.md +103 -0
  136. package/.codex/skills/security-guard/references/sensitive-strategies.md +42 -0
  137. package/.codex/skills/sms-mail/SKILL.md +116 -574
  138. package/.codex/skills/sms-mail/references/mail-config.md +88 -0
  139. package/.codex/skills/sms-mail/references/sms-config.md +74 -0
  140. package/.codex/skills/social-login/SKILL.md +112 -514
  141. package/.codex/skills/social-login/references/provider-configs.md +118 -0
  142. package/.codex/skills/store-pc/SKILL.md +258 -383
  143. package/.codex/skills/tenant-management/SKILL.md +129 -444
  144. package/.codex/skills/tenant-management/references/tenant-scenarios.md +91 -0
  145. package/.codex/skills/test-development/SKILL.md +86 -540
  146. package/.codex/skills/test-development/references/parameterized-examples.md +119 -0
  147. package/.codex/skills/ui-pc/SKILL.md +350 -387
  148. package/.codex/skills/utils-toolkit/SKILL.md +52 -283
  149. package/.codex/skills/utils-toolkit/references/redis-utils-api.md +56 -0
  150. package/.codex/skills/websocket-sse/SKILL.md +105 -550
  151. package/.codex/skills/workflow-engine/SKILL.md +147 -502
  152. package/.cursor/hooks.json +3 -3
  153. package/.cursor/skills/add-skill/SKILL.md +79 -32
  154. package/.cursor/skills/api-development/SKILL.md +83 -377
  155. package/.cursor/skills/architecture-design/SKILL.md +138 -632
  156. package/.cursor/skills/backend-annotations/SKILL.md +134 -506
  157. package/.cursor/skills/banana-image/SKILL.md +10 -3
  158. package/.cursor/skills/brainstorm/SKILL.md +103 -535
  159. package/.cursor/skills/bug-detective/SKILL.md +147 -1097
  160. package/.cursor/skills/bug-detective/references/error-patterns.md +242 -0
  161. package/.cursor/skills/code-patterns/SKILL.md +116 -426
  162. package/.cursor/skills/code-patterns/references/leniu-code-patterns.md +87 -0
  163. package/.cursor/skills/crud-development/SKILL.md +64 -304
  164. package/.cursor/skills/data-permission/SKILL.md +105 -412
  165. package/.cursor/skills/data-permission/references/custom-data-scope.md +90 -0
  166. package/.cursor/skills/file-oss-management/SKILL.md +106 -714
  167. package/.cursor/skills/file-oss-management/references/entities.md +105 -0
  168. package/.cursor/skills/file-oss-management/references/service-impl.md +104 -0
  169. package/.cursor/skills/git-workflow/SKILL.md +27 -5
  170. package/.cursor/skills/leniu-api-development/SKILL.md +142 -626
  171. package/.cursor/skills/leniu-api-development/references/real-examples.md +273 -0
  172. package/.cursor/skills/leniu-architecture-design/SKILL.md +176 -391
  173. package/.cursor/skills/leniu-backend-annotations/SKILL.md +132 -519
  174. package/.cursor/skills/leniu-brainstorm/SKILL.md +132 -541
  175. package/.cursor/skills/leniu-brainstorm/references/business-scenarios.md +162 -0
  176. package/.cursor/skills/leniu-crud-development/SKILL.md +232 -938
  177. package/.cursor/skills/leniu-crud-development/references/templates.md +597 -0
  178. package/.cursor/skills/leniu-customization-location/SKILL.md +410 -0
  179. package/.cursor/skills/leniu-data-permission/SKILL.md +70 -0
  180. package/.cursor/skills/leniu-java-code-style/SKILL.md +510 -0
  181. package/.cursor/skills/leniu-java-entity/SKILL.md +76 -590
  182. package/.cursor/skills/leniu-java-entity/references/templates.md +237 -0
  183. package/.cursor/skills/leniu-java-export/SKILL.md +94 -379
  184. package/.cursor/skills/leniu-java-logging/SKILL.md +106 -709
  185. package/.cursor/skills/leniu-java-logging/references/data-mask.md +46 -0
  186. package/.cursor/skills/leniu-java-logging/references/logging-scenarios.md +113 -0
  187. package/.cursor/skills/leniu-java-mybatis/SKILL.md +73 -446
  188. package/.cursor/skills/leniu-java-mybatis/references/report-mapper.md +88 -0
  189. package/.cursor/skills/leniu-report-customization/SKILL.md +111 -365
  190. package/.cursor/skills/leniu-report-customization/references/table-fields.md +93 -0
  191. package/.cursor/skills/leniu-report-standard-customization/SKILL.md +111 -334
  192. package/.cursor/skills/leniu-report-standard-customization/references/analysis-module.md +64 -0
  193. package/.cursor/skills/leniu-report-standard-customization/references/table-fields.md +113 -0
  194. package/.cursor/skills/leniu-security-guard/SKILL.md +133 -347
  195. package/.cursor/skills/mysql-debug/SKILL.md +364 -0
  196. package/.cursor/skills/openspec-apply-change/SKILL.md +10 -1
  197. package/.cursor/skills/openspec-archive-change/SKILL.md +9 -1
  198. package/.cursor/skills/openspec-bulk-archive-change/SKILL.md +9 -1
  199. package/.cursor/skills/openspec-continue-change/SKILL.md +9 -1
  200. package/.cursor/skills/openspec-explore/SKILL.md +10 -1
  201. package/.cursor/skills/openspec-ff-change/SKILL.md +9 -1
  202. package/.cursor/skills/openspec-new-change/SKILL.md +9 -1
  203. package/.cursor/skills/openspec-onboard/SKILL.md +15 -130
  204. package/.cursor/skills/openspec-sync-specs/SKILL.md +9 -1
  205. package/.cursor/skills/openspec-verify-change/SKILL.md +9 -1
  206. package/.cursor/skills/performance-doctor/SKILL.md +110 -434
  207. package/.cursor/skills/redis-cache/SKILL.md +89 -595
  208. package/.cursor/skills/redis-cache/references/listeners.md +23 -0
  209. package/.cursor/skills/scheduled-jobs/SKILL.md +88 -407
  210. package/.cursor/skills/security-guard/SKILL.md +137 -532
  211. package/.cursor/skills/security-guard/references/encrypt-config.md +103 -0
  212. package/.cursor/skills/security-guard/references/sensitive-strategies.md +42 -0
  213. package/.cursor/skills/sms-mail/SKILL.md +116 -574
  214. package/.cursor/skills/sms-mail/references/mail-config.md +88 -0
  215. package/.cursor/skills/sms-mail/references/sms-config.md +74 -0
  216. package/.cursor/skills/social-login/SKILL.md +112 -514
  217. package/.cursor/skills/social-login/references/provider-configs.md +118 -0
  218. package/.cursor/skills/tenant-management/SKILL.md +129 -444
  219. package/.cursor/skills/tenant-management/references/tenant-scenarios.md +91 -0
  220. package/.cursor/skills/test-development/SKILL.md +86 -540
  221. package/.cursor/skills/test-development/references/parameterized-examples.md +119 -0
  222. package/.cursor/skills/utils-toolkit/SKILL.md +52 -305
  223. package/.cursor/skills/utils-toolkit/references/redis-utils-api.md +56 -0
  224. package/.cursor/skills/websocket-sse/SKILL.md +105 -550
  225. package/.cursor/skills/workflow-engine/SKILL.md +147 -502
  226. package/package.json +1 -1
@@ -1,416 +1,261 @@
1
1
  ---
2
2
  name: leniu-security-guard
3
3
  description: |
4
- leniu-tengyun-core / leniu-yunshitang 项目安全权限控制规范。包含认证注解、SQL注入防护、XSS防护、数据脱敏、限流防重放。
4
+ leniu-tengyun-core / leniu-yunshitang 项目安全权限控制规范。包含认证注解体系、TokenManager API、数据权限校验、SQL注入防护。
5
5
 
6
6
  触发场景:
7
- - 配置接口认证注解(@RequiresAuthentication/@RequiresGuest)
8
- - SQL 注入(#{} 参数化查询)
9
- - XSS/CSRF 防护
10
- - 数据脱敏(密码、手机号)
11
- - 限流和防重放攻击
7
+ - 配置接口认证注解(@RequiresAuthentication/@RequiresGuest/@RequiresPermissions
8
+ - 使用 TokenManager 获取用户信息或校验权限
9
+ - SQL 注入(MyBatis #{} 参数化查询)
10
+ - 数据归属校验(防越权)
11
+ - VO 敏感字段脱敏处理
12
12
 
13
13
  适用项目:
14
14
  - leniu-tengyun-core:/Users/xujiajun/Developer/gongsi_proj/leniu-api/leniu-tengyun-core
15
15
  - leniu-yunshitang:/Users/xujiajun/Developer/gongsi_proj/leniu-api/leniu-tengyun/leniu-yunshitang
16
16
 
17
- 触发词:安全认证、SQL注入防护、XSS防护、数据脱敏、SM4加密、接口安全、限流
17
+ 触发词:安全认证、权限注解、TokenManager、SQL注入防护、数据脱敏、接口安全、RequiresAuthentication
18
18
  ---
19
19
 
20
20
  # leniu-security-guard
21
21
 
22
- 适用于 leniu-tengyun-core / leniu-yunshitang 项目的安全权限控制。
23
-
24
22
  ## 认证注解
25
23
 
26
- | 注解 | 用途 | 位置 |
27
- |------|------|------|
28
- | `@RequiresAuthentication` | 需要登录认证 | `net.xnzn.framework.secure.filter.annotation.RequiresAuthentication` |
29
- | `@RequiresGuest` | 允许游客访问 | `net.xnzn.framework.secure.filter.annotation.RequiresGuest` |
30
- | `@RequiresPermissions` | 需要指定权限 | `net.xnzn.framework.secure.filter.annotation.RequiresPermissions` |
31
- | `@RequiresRoles` | 需要指定角色 | `net.xnzn.framework.secure.filter.annotation.RequiresRoles` |
32
- | `@RequiresUser` | 需要用户登录 | `net.xnzn.framework.secure.filter.annotation.RequiresUser` |
33
- | `@RequiresHeader` | 需要指定请求头 | `net.xnzn.framework.secure.filter.annotation.RequiresHeader` |
24
+ 所有注解包路径:`net.xnzn.framework.secure.filter.annotation.*`
34
25
 
35
- ## 基础用法
26
+ | 注解 | 用途 |
27
+ |------|------|
28
+ | `@RequiresAuthentication` | 需要登录认证(最常用,类/方法级) |
29
+ | `@RequiresGuest` | 允许游客访问(公开接口) |
30
+ | `@RequiresPermissions` | 需要指定权限码 |
31
+ | `@RequiresRoles` | 需要指定角色 |
32
+ | `@RequiresUser` | 需要用户登录 |
33
+ | `@RequiresHeader` | 需要指定请求头 |
36
34
 
37
- ### Controller 认证
35
+ ### Controller 认证示例
38
36
 
39
37
  ```java
40
38
  import net.xnzn.framework.secure.filter.annotation.RequiresAuthentication;
41
39
  import net.xnzn.framework.secure.filter.annotation.RequiresGuest;
40
+ import net.xnzn.framework.secure.filter.annotation.RequiresPermissions;
41
+ import net.xnzn.framework.secure.filter.annotation.RequiresRoles;
42
42
 
43
- // 需要登录认证
43
+ // 类级别:整个 Controller 需要登录
44
44
  @RestController
45
- @RequestMapping("/api/v2/xxx")
45
+ @RequestMapping("/api/v2/web/xxx")
46
46
  @RequiresAuthentication
47
- public class XxxController {
48
- // ...
49
- }
47
+ public class XxxWebController { }
50
48
 
51
- // 允许游客访问(无需登录)
49
+ // 方法级别:允许游客访问
52
50
  @GetMapping("/public/info")
53
51
  @RequiresGuest
54
- public LeResponse<String> getPublicInfo() {
55
- return LeResponse.succ("public data");
56
- }
52
+ public LeResponse<String> getPublicInfo() { }
57
53
 
58
54
  // 需要特定权限
59
55
  @GetMapping("/admin/users")
60
56
  @RequiresPermissions("system:user:list")
61
- public LeResponse<List<User>> listUsers() {
62
- return LeResponse.succ(userService.list());
63
- }
57
+ public LeResponse<List<User>> listUsers() { }
64
58
 
65
- // 需要所有指定权限(AND 逻辑,默认)
59
+ // AND 逻辑(默认):需要所有权限
66
60
  @RequiresPermissions(value = {"system:user:add", "system:user:edit"}, logical = Logical.AND)
67
- public LeResponse<Void> addUser(User user) { }
68
61
 
69
- // 需要任一权限(OR 逻辑)
62
+ // OR 逻辑:需要任一权限
70
63
  @RequiresPermissions(value = {"system:user:add", "system:user:edit"}, logical = Logical.OR)
71
- public LeResponse<Void> editUser(User user) { }
72
64
 
73
65
  // 需要指定角色
74
66
  @RequiresRoles("admin")
75
- public LeResponse<Void> adminAction() { }
76
67
 
77
68
  // 需要所有角色
78
69
  @RequiresRoles(value = {"admin", "manager"}, logical = Logical.AND)
79
- public LeResponse<Void> superAction() { }
80
70
  ```
81
71
 
82
- ### Service 层获取用户信息
72
+ > **注意**:`@RequiresPermissions` 不指定 `value` 时,自动使用 `@RequestMapping` 路径作为权限码。
73
+
74
+ ---
75
+
76
+ ## TokenManager API
83
77
 
84
78
  ```java
85
79
  import net.xnzn.framework.secure.token.TokenManager;
80
+ ```
86
81
 
87
- // 检查是否登录
88
- if (TokenManager.isLogin()) {
89
- // 已登录
90
- }
82
+ ### 用户信息
83
+
84
+ ```java
85
+ // 登录状态
86
+ TokenManager.isLogin();
91
87
 
92
- // 获取用户 ID
88
+ // 用户 ID
93
89
  Long userId = TokenManager.getSubjectId().orElse(null);
94
90
 
95
- // 获取用户名
91
+ // 用户名
96
92
  String userName = TokenManager.getSubjectName().orElse(null);
97
93
 
98
- // 获取附加数据
94
+ // 附加数据
99
95
  Map<String, String> userData = TokenManager.getSubjectData();
100
96
  String orgId = userData.get("orgId");
97
+ ```
101
98
 
102
- // 检查权限
103
- if (TokenManager.hasPermission("system:user:add")) {
104
- // 有权限
105
- }
99
+ ### 权限/角色校验
106
100
 
107
- // 检查多个权限(AND)
108
- if (TokenManager.hasPermission("system:user:add", "system:user:edit")) {
109
- // 拥有所有权限
110
- }
101
+ ```java
102
+ // 单个权限
103
+ TokenManager.hasPermission("system:user:add");
111
104
 
112
- // 检查任一权限(OR
113
- if (TokenManager.hasAnyPermission("system:user:add", "system:user:edit")) {
114
- // 拥有任一权限
115
- }
105
+ // 多个权限(AND
106
+ TokenManager.hasPermission("system:user:add", "system:user:edit");
116
107
 
117
- // 检查角色
118
- if (TokenManager.hasRole("admin")) {
119
- // 是管理员
120
- }
108
+ // 任一权限(OR)
109
+ TokenManager.hasAnyPermission("system:user:add", "system:user:edit");
121
110
 
122
- // 检查任一角色
123
- if (TokenManager.hasAnyRole("admin", "manager")) {
124
- // 是管理员或经理
125
- }
111
+ // 角色
112
+ TokenManager.hasRole("admin");
113
+ TokenManager.hasAnyRole("admin", "manager");
126
114
  ```
127
115
 
128
- ### 附加用户数据
116
+ ### 附加数据管理
129
117
 
130
118
  ```java
131
- // 添加附加数据到 Token
119
+ // 添加
132
120
  TokenManager.attachData("orgId", "12345");
133
- TokenManager.attachData("deptId", "67890");
134
121
 
135
122
  // 批量添加
136
- Map<String, String> data = new HashMap<>();
137
- data.put("orgId", "12345");
138
- data.put("deptId", "67890");
139
- TokenManager.attachData(data);
123
+ TokenManager.attachData(Map.of("orgId", "12345", "deptId", "67890"));
140
124
 
141
- // 获取附加数据
142
- Map<String, String> userData = TokenManager.getSubjectData();
143
- String orgId = userData.get("orgId");
125
+ // 获取
126
+ String orgId = TokenManager.getSubjectData().get("orgId");
144
127
 
145
- // 移除附加数据
128
+ // 移除
146
129
  TokenManager.removeData("orgId", "deptId");
147
130
  ```
148
131
 
149
- ### 登出操作
132
+ ### 登出与缓存
150
133
 
151
134
  ```java
152
- // 登出当前用户
135
+ // 登出
153
136
  TokenManager.logout();
154
137
 
155
- // 撤销认证(强制下线)
138
+ // 强制下线
156
139
  TokenManager.revokeAuthenticate();
157
140
 
158
- // 撤销指定用户的旧 Token(保留最近 N 个)
141
+ // 撤销旧 Token(保留最近 N 个)
159
142
  TokenManager.revokeAuthenticate(userId, 3);
160
- ```
161
143
 
162
- ### 权限缓存管理
163
-
164
- ```java
165
- // 清除用户权限缓存
144
+ // 清除权限/角色缓存
166
145
  TokenManager.clearPermission(userId);
167
-
168
- // 清除用户角色缓存
169
146
  TokenManager.clearRole(userId);
170
-
171
- // 清除用户权限和角色缓存
172
147
  TokenManager.clearRoleAndPermission(userId);
173
-
174
- // 清除所有权限缓存
175
148
  TokenManager.clearAllRoleAndPermission();
176
149
  ```
177
150
 
178
- ## WebContext 使用
151
+ ---
152
+
153
+ ## WebContext
179
154
 
180
155
  ```java
181
156
  import net.xnzn.framework.secure.WebContext;
182
157
 
183
- // 获取当前请求
184
158
  HttpServletRequest request = WebContext.get().getRequest().orElse(null);
185
-
186
- // 获取当前响应
187
159
  HttpServletResponse response = WebContext.get().getResponse().orElse(null);
188
-
189
- // 获取 AccessToken
190
160
  Optional<AccessToken> token = WebContext.get().getAccessToken();
191
161
 
192
- // 设置/获取属性
193
- WebContext.get().setAttribute("customKey", "customValue");
194
- Object value = WebContext.get().getAttribute("customKey");
195
-
196
- // 清除上下文
162
+ // 属性存取
163
+ WebContext.get().setAttribute("key", "value");
164
+ Object value = WebContext.get().getAttribute("key");
197
165
  WebContext.reset();
198
166
  ```
199
167
 
200
- ## SQL 注入防护
201
-
202
- ### 使用参数化查询(MyBatis #{} 占位符)
203
-
204
- ```java
205
- // ❌ 错误:字符串拼接有注入风险
206
- String sql = "SELECT * FROM user WHERE name = '" + name + "'";
207
-
208
- // ✅ 正确:使用 MyBatis 参数化查询
209
- mapper.selectByName(name); // MyBatis 内部使用 #{name}
210
- ```
211
-
212
- ### MyBatis XML 中必须使用 `#{}`
213
-
214
- ```xml
215
- <!-- ✅ 正确:使用 #{} -->
216
- <select id="selectByName" resultType="User">
217
- SELECT id, name, mobile FROM user WHERE name = #{name}
218
- </select>
219
-
220
- <!-- ❌ 错误:使用 ${} 有 SQL 注入风险 -->
221
- <select id="selectByName" resultType="User">
222
- SELECT * FROM user WHERE name = '${name}'
223
- </select>
224
- ```
225
-
226
- ### 禁止 SELECT *
227
-
228
- ```xml
229
- <!-- ❌ 错误:使用 SELECT * -->
230
- <select id="queryList">
231
- SELECT * FROM user WHERE status = #{status}
232
- </select>
233
-
234
- <!-- ✅ 正确:明确指定字段 -->
235
- <select id="queryList">
236
- SELECT id, name, mobile, status FROM user WHERE status = #{status}
237
- </select>
238
- ```
239
-
240
- ## XSS 防护
241
-
242
- ### 输出时转义
243
-
244
- ```java
245
- // 使用 Spring 的 HtmlUtils 转义
246
- String safeContent = HtmlUtils.htmlEscape(userInput);
247
-
248
- // 或使用 Apache Commons Text
249
- String safeContent = StringEscapeUtils.escapeHtml4(userInput);
250
- ```
251
-
252
- ### VO 中使用 @JsonSerialize
253
-
254
- ```java
255
- @Data
256
- public class ArticleVO {
257
- @JsonSerialize(using = HtmlEscapeSerializer.class)
258
- private String content; // 自动转义 HTML
259
- }
260
- ```
168
+ ---
261
169
 
262
170
  ## 数据权限校验(防越权)
263
171
 
264
172
  ```java
265
173
  @Transactional(rollbackFor = Exception.class)
266
174
  public void delete(Long id) {
267
- // 查询数据
268
175
  Order order = orderMapper.selectById(id);
269
176
  Assert.notNull(order, () -> new LeException("订单不存在"));
270
177
 
271
178
  // 校验数据归属
272
- Long currentUserId = TokenManager.getSubjectId().orElseThrow(
273
- () -> new LeException("用户未登录")
274
- );
179
+ Long currentUserId = TokenManager.getSubjectId()
180
+ .orElseThrow(() -> new LeException("用户未登录"));
275
181
  if (!order.getUserId().equals(currentUserId)) {
276
182
  throw new LeException("无权操作该订单");
277
183
  }
278
184
 
279
- // 执行删除
280
185
  orderMapper.deleteById(id);
281
186
  }
282
187
  ```
283
188
 
284
- ## 数据脱敏
285
-
286
- ### 日志脱敏
189
+ ### 最小权限原则
287
190
 
288
191
  ```java
289
- // ❌ 错误:记录敏感信息
290
- log.info("用户登录,username:{}, password:{}", username, password);
291
-
292
- // 正确:不记录敏感信息
293
- log.info("用户登录,username:{}", username);
192
+ @RequiresAuthentication
193
+ @RequiresPermissions("order:view")
194
+ public PageVO<OrderVO> pageList(OrderPageParam param) {
195
+ Long userId = TokenManager.getSubjectId()
196
+ .orElseThrow(() -> new LeException("用户未登录"));
197
+ param.setUserId(userId); // 限制只查自己的数据
198
+ return orderService.pageList(param);
199
+ }
294
200
  ```
295
201
 
296
- ### 手机号 / 身份证 / 银行卡脱敏
202
+ ---
297
203
 
298
- ```java
299
- // 手机号脱敏
300
- public static String maskMobile(String mobile) {
301
- if (StrUtil.isBlank(mobile) || mobile.length() != 11) {
302
- return mobile;
303
- }
304
- return mobile.substring(0, 3) + "****" + mobile.substring(7);
305
- }
204
+ ## SQL 注入防护
306
205
 
307
- // 身份证脱敏
308
- public static String maskIdCard(String idCard) {
309
- if (StrUtil.isBlank(idCard) || idCard.length() < 8) {
310
- return idCard;
311
- }
312
- return idCard.substring(0, 4) + "**********" + idCard.substring(idCard.length() - 4);
313
- }
206
+ ### MyBatis XML 必须用 `#{}`
314
207
 
315
- // 银行卡脱敏
316
- public static String maskBankCard(String bankCard) {
317
- if (StrUtil.isBlank(bankCard) || bankCard.length() < 8) {
318
- return bankCard;
319
- }
320
- return bankCard.substring(0, 4) + " **** **** " + bankCard.substring(bankCard.length() - 4);
321
- }
208
+ ```xml
209
+ <!-- 正确:参数化查询 -->
210
+ <select id="selectByName" resultType="User">
211
+ SELECT id, name, mobile FROM user WHERE name = #{name}
212
+ </select>
213
+
214
+ <!-- 错误:${} 有注入风险 -->
215
+ <select id="selectByName" resultType="User">
216
+ SELECT * FROM user WHERE name = '${name}'
217
+ </select>
218
+ ```
219
+
220
+ ### 禁止 SELECT *
221
+
222
+ ```xml
223
+ <!-- 错误 -->
224
+ SELECT * FROM user WHERE status = #{status}
225
+
226
+ <!-- 正确:明确指定字段 -->
227
+ SELECT id, name, mobile, status FROM user WHERE status = #{status}
322
228
  ```
323
229
 
324
- ### VO 中敏感字段处理
230
+ ---
231
+
232
+ ## VO 敏感字段处理
325
233
 
326
234
  ```java
327
235
  @Data
328
236
  public class UserVO {
329
- // 密码绝不返回
330
237
  @JsonIgnore
331
- private String password;
238
+ private String password; // 密码绝不返回
332
239
 
333
- // 手机号脱敏
334
240
  @JsonSerialize(using = MobileSerializer.class)
335
- private String mobile;
241
+ private String mobile; // 手机号脱敏
336
242
 
337
- // 身份证脱敏
338
243
  @JsonSerialize(using = IdCardSerializer.class)
339
- private String idCard;
340
- }
341
- ```
342
-
343
- ## BCrypt 密码安全
344
-
345
- ```java
346
- @Autowired
347
- private PasswordEncoder passwordEncoder;
348
-
349
- // 注册时加密密码(BCrypt)
350
- public void register(UserParam param) {
351
- User user = new User();
352
- user.setUsername(param.getUsername());
353
- user.setPassword(passwordEncoder.encode(param.getPassword()));
354
- userMapper.insert(user);
355
- }
356
-
357
- // 登录时验证密码
358
- public void login(String username, String password) {
359
- User user = userMapper.selectByUsername(username);
360
- if (user == null) {
361
- throw new LeException("用户不存在");
362
- }
363
- if (!passwordEncoder.matches(password, user.getPassword())) {
364
- throw new LeException("密码错误");
365
- }
244
+ private String idCard; // 身份证脱敏
366
245
  }
367
246
  ```
368
247
 
369
- ## 防重放攻击
248
+ ### 日志脱敏
370
249
 
371
250
  ```java
372
- public void processRequest(ApiRequest request) {
373
- // 1. 校验时间戳(5 分钟内有效)
374
- long timestamp = request.getTimestamp();
375
- long now = System.currentTimeMillis();
376
- if (Math.abs(now - timestamp) > 5 * 60 * 1000) {
377
- throw new LeException("请求已过期");
378
- }
379
-
380
- // 2. 校验签名
381
- String sign = request.getSign();
382
- String expectedSign = generateSign(request);
383
- if (!sign.equals(expectedSign)) {
384
- throw new LeException("签名验证失败");
385
- }
386
-
387
- // 3. 校验 nonce(防止重放)
388
- String nonce = request.getNonce();
389
- if (redisTemplate.hasKey("nonce:" + nonce)) {
390
- throw new LeException("请求已处理");
391
- }
392
-
393
- // 4. 记录 nonce(5 分钟有效)
394
- redisTemplate.opsForValue().set("nonce:" + nonce, "1", 5, TimeUnit.MINUTES);
251
+ // 错误:记录敏感信息
252
+ log.info("用户登录, username:{}, password:{}", username, password);
395
253
 
396
- // 5. 处理业务
397
- doProcess(request);
398
- }
254
+ // 正确:不记录密码
255
+ log.info("用户登录, username:{}", username);
399
256
  ```
400
257
 
401
- ## 限流防护(Redis 计数器)
402
-
403
- ```java
404
- public void checkRateLimit(Long userId, String api, int limit, int seconds) {
405
- String key = String.format("rate:%d:%s", userId, api);
406
- Integer count = RedisUtil.incr(key, (long) seconds);
407
-
408
- // 首次请求已由 incr 设置过期时间
409
- if (count > limit) {
410
- throw new LeException("请求过于频繁,请稍后重试");
411
- }
412
- }
413
- ```
258
+ ---
414
259
 
415
260
  ## 输入验证
416
261
 
@@ -434,87 +279,28 @@ public class UserParam {
434
279
  }
435
280
  ```
436
281
 
437
- ## 文件上传校验
438
-
439
- ```java
440
- public String uploadFile(MultipartFile file) {
441
- // 1. 校验文件是否为空
442
- if (file == null || file.isEmpty()) {
443
- throw new LeException("文件不能为空");
444
- }
445
-
446
- // 2. 校验文件大小(10MB)
447
- if (file.getSize() > 10 * 1024 * 1024) {
448
- throw new LeException("文件大小不能超过10MB");
449
- }
450
-
451
- // 3. 白名单校验文件类型(白名单优于黑名单)
452
- String contentType = file.getContentType();
453
- List<String> allowedTypes = Arrays.asList("image/jpeg", "image/png", "image/gif");
454
- if (!allowedTypes.contains(contentType)) {
455
- throw new LeException("不支持的文件类型");
456
- }
457
-
458
- // 4. 校验文件扩展名
459
- String filename = file.getOriginalFilename();
460
- String extension = filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();
461
- List<String> allowedExtensions = Arrays.asList("jpg", "jpeg", "png", "gif");
462
- if (!allowedExtensions.contains(extension)) {
463
- throw new LeException("不支持的文件扩展名");
464
- }
465
-
466
- // 5. 生成安全的文件名(避免路径穿越)
467
- String safeFilename = UUID.randomUUID().toString() + "." + extension;
468
-
469
- return fileService.upload(file, safeFilename);
470
- }
471
- ```
282
+ ---
472
283
 
473
- ## 最小权限原则
284
+ ## 限流防护
474
285
 
475
286
  ```java
476
- // 只授予必要的权限,且限制用户只能操作自己的数据
477
- @RequiresAuthentication
478
- @RequiresPermissions("order:view")
479
- public PageVO<OrderVO> pageList(OrderPageParam param) {
480
- Long userId = TokenManager.getSubjectId().orElseThrow(
481
- () -> new LeException("用户未登录")
482
- );
483
- param.setUserId(userId);
484
- return orderService.pageList(param);
287
+ // Redis 计数器限流
288
+ public void checkRateLimit(Long userId, String api, int limit, int seconds) {
289
+ String key = String.format("rate:%d:%s", userId, api);
290
+ Integer count = RedisUtil.incr(key, (long) seconds);
291
+ if (count > limit) {
292
+ throw new LeException("请求过于频繁,请稍后重试");
293
+ }
485
294
  }
486
295
  ```
487
296
 
488
- ## 安全的随机数
489
-
490
- ```java
491
- // ✅ 使用 SecureRandom(密码学安全)
492
- SecureRandom random = new SecureRandom();
493
- byte[] bytes = new byte[32];
494
- random.nextBytes(bytes);
495
-
496
- // ❌ 不安全:使用 Random(可预测)
497
- Random random = new Random();
498
- ```
499
-
500
- ## 与 RuoYi-Plus 的区别
501
-
502
- | 特性 | RuoYi-Plus | leniu-tengyun-core |
503
- |------|-----------|-------------------|
504
- | 权限注解 | `@SaCheckPermission("system:user:list")` | `@RequiresPermissions("system:user:list")` |
505
- | 角色注解 | `@SaCheckRole("admin")` | `@RequiresRoles("admin")` |
506
- | 登录检查 | `StpUtil.isLogin()` | `TokenManager.isLogin()` |
507
- | 获取用户 ID | `StpUtil.getLoginIdAsLong()` | `TokenManager.getSubjectId()` |
508
- | 权限检查 | `StpUtil.hasPermission("key")` | `TokenManager.hasPermission("key")` |
509
- | 角色检查 | `StpUtil.hasRole("admin")` | `TokenManager.hasRole("admin")` |
510
- | 登出 | `StpUtil.logout()` | `TokenManager.logout()` |
297
+ ---
511
298
 
512
299
  ## 注意事项
513
300
 
514
- 1. `@RequiresPermissions` 注解如果不指定 `value`,会自动使用 `@RequestMapping` 的路径作为权限码
515
- 2. 权限和角色数据会自动缓存到 Redis,可以通过 `clearPermission/clearRole` 手动清除
516
- 3. `TokenManager` 方法都需要在已登录的上下文中使用
517
- 4. `@RequiresGuest` 注解用于公开接口,不需要登录
518
- 5. MyBatis XML 中必须使用 `#{}` 而非 `${}`,防止 SQL 注入
519
- 6. VO 中密码字段必须使用 `@JsonIgnore`,手机号等敏感字段使用序列化脱敏
520
- 7. 限流 key 格式:`rate:{userId}:{api}`,防重放 key 格式:`nonce:{nonce}`
301
+ 1. 权限和角色数据自动缓存到 Redis,通过 `clearPermission/clearRole` 手动清除
302
+ 2. `TokenManager` 方法需在已登录上下文中使用
303
+ 3. `@RequiresGuest` 用于公开接口,不需要登录
304
+ 4. MyBatis XML 中必须使用 `#{}` 而非 `${}`
305
+ 5. VO 中密码字段必须 `@JsonIgnore`,手机号等用序列化脱敏
306
+ 6. 限流 key 格式:`rate:{userId}:{api}`