ai-engineering-init 1.1.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/agents/code-reviewer.md +139 -0
- package/.claude/agents/project-manager.md +159 -0
- package/.claude/audio/completed.wav +0 -0
- package/.claude/commands/add-todo.md +255 -0
- package/.claude/commands/check.md +210 -0
- package/.claude/commands/crud.md +454 -0
- package/.claude/commands/dev.md +503 -0
- package/.claude/commands/init-docs.md +681 -0
- package/.claude/commands/next.md +251 -0
- package/.claude/commands/progress.md +242 -0
- package/.claude/commands/start.md +199 -0
- package/.claude/commands/sync.md +307 -0
- package/.claude/commands/update-status.md +428 -0
- package/.claude/docs/Mixin/344/275/277/347/224/250/346/214/207/345/215/227.md +299 -0
- package/.claude/docs/README.md +167 -0
- package/.claude/docs//345/211/215/347/253/257/345/274/200/345/217/221/346/214/207/345/215/227.md +599 -0
- package/.claude/docs//345/220/216/347/253/257/345/274/200/345/217/221/346/214/207/345/215/227.md +726 -0
- package/.claude/docs//345/267/245/344/275/234/346/265/201/345/274/200/345/217/221/346/214/207/345/215/227.md +714 -0
- package/.claude/docs//345/267/245/345/205/267/347/261/273/344/275/277/347/224/250/346/214/207/345/215/227.md +463 -0
- package/.claude/docs//346/225/260/346/215/256/345/272/223/350/256/276/350/256/241/350/247/204/350/214/203.md +390 -0
- package/.claude/docs//346/226/260/345/212/237/350/203/275/345/274/200/345/217/221/346/265/201/347/250/213/350/247/204/350/214/203.md +688 -0
- package/.claude/docs//346/226/260/351/241/271/347/233/256/345/274/200/345/217/221/346/265/201/347/250/213.md +365 -0
- package/.claude/docs//346/241/206/346/236/266/350/257/264/346/230/216.md +393 -0
- package/.claude/docs//350/267/257/347/224/261/351/205/215/347/275/256/346/214/207/345/215/227.md +246 -0
- package/.claude/framework-config.json +73 -0
- package/.claude/hooks/pre-tool-use.js +117 -0
- package/.claude/hooks/skill-forced-eval.js +167 -0
- package/.claude/hooks/stop.js +58 -0
- package/.claude/settings.json +41 -0
- package/.claude/skills/add-skill/SKILL.md +352 -0
- package/.claude/skills/api-development/SKILL.md +560 -0
- package/.claude/skills/architecture-design/SKILL.md +756 -0
- package/.claude/skills/backend-annotations/SKILL.md +674 -0
- package/.claude/skills/banana-image/CHANGELOG.md +37 -0
- package/.claude/skills/banana-image/README.md +146 -0
- package/.claude/skills/banana-image/SKILL.md +164 -0
- package/.claude/skills/banana-image/assets/logo.png +0 -0
- package/.claude/skills/banana-image/references/advanced-usage.md +189 -0
- package/.claude/skills/banana-image/scripts/apply_template.py +125 -0
- package/.claude/skills/banana-image/scripts/banana_image_exec.ts +412 -0
- package/.claude/skills/banana-image/scripts/batch_prep.py +82 -0
- package/.claude/skills/banana-image/scripts/package-lock.json +1437 -0
- package/.claude/skills/banana-image/scripts/package.json +18 -0
- package/.claude/skills/banana-image/scripts/requirements.txt +10 -0
- package/.claude/skills/banana-image/templates/poster.json +22 -0
- package/.claude/skills/banana-image/templates/product.json +17 -0
- package/.claude/skills/banana-image/templates/social.json +22 -0
- package/.claude/skills/banana-image/templates/thumbnail.json +17 -0
- package/.claude/skills/brainstorm/SKILL.md +648 -0
- package/.claude/skills/bug-detective/SKILL.md +1206 -0
- package/.claude/skills/code-patterns/SKILL.md +590 -0
- package/.claude/skills/collaborating-with-codex/SKILL.md +174 -0
- package/.claude/skills/collaborating-with-codex/scripts/codex_bridge.py +275 -0
- package/.claude/skills/collaborating-with-gemini/SKILL.md +194 -0
- package/.claude/skills/collaborating-with-gemini/scripts/gemini_bridge.py +275 -0
- package/.claude/skills/crud-development/SKILL.md +649 -0
- package/.claude/skills/data-permission/SKILL.md +599 -0
- package/.claude/skills/database-ops/SKILL.md +407 -0
- package/.claude/skills/error-handler/SKILL.md +371 -0
- package/.claude/skills/file-oss-management/SKILL.md +863 -0
- package/.claude/skills/git-workflow/SKILL.md +375 -0
- package/.claude/skills/json-serialization/SKILL.md +357 -0
- package/.claude/skills/leniu-api-development/SKILL.md +803 -0
- package/.claude/skills/leniu-architecture-design/SKILL.md +598 -0
- package/.claude/skills/leniu-backend-annotations/SKILL.md +664 -0
- package/.claude/skills/leniu-code-patterns/SKILL.md +365 -0
- package/.claude/skills/leniu-crud-development/SKILL.md +1110 -0
- package/.claude/skills/leniu-data-permission/SKILL.md +256 -0
- package/.claude/skills/leniu-database-ops/SKILL.md +426 -0
- package/.claude/skills/leniu-error-handler/SKILL.md +462 -0
- package/.claude/skills/leniu-java-amount-handling/SKILL.md +461 -0
- package/.claude/skills/leniu-java-code-style/SKILL.md +510 -0
- package/.claude/skills/leniu-java-concurrent/SKILL.md +400 -0
- package/.claude/skills/leniu-java-entity/SKILL.md +751 -0
- package/.claude/skills/leniu-java-export/SKILL.md +560 -0
- package/.claude/skills/leniu-java-logging/SKILL.md +832 -0
- package/.claude/skills/leniu-java-mq/SKILL.md +338 -0
- package/.claude/skills/leniu-java-mybatis/SKILL.md +640 -0
- package/.claude/skills/leniu-java-report-query-param/SKILL.md +291 -0
- package/.claude/skills/leniu-java-task/SKILL.md +367 -0
- package/.claude/skills/leniu-java-total-line/SKILL.md +195 -0
- package/.claude/skills/leniu-marketing-price-rule-customizer/SKILL.md +301 -0
- package/.claude/skills/leniu-marketing-recharge-rule-customizer/SKILL.md +285 -0
- package/.claude/skills/leniu-mealtime/SKILL.md +215 -0
- package/.claude/skills/leniu-redis-cache/SKILL.md +316 -0
- package/.claude/skills/leniu-security-guard/SKILL.md +520 -0
- package/.claude/skills/leniu-utils-toolkit/SKILL.md +380 -0
- package/.claude/skills/openspec-apply-change/SKILL.md +156 -0
- package/.claude/skills/openspec-archive-change/SKILL.md +114 -0
- package/.claude/skills/openspec-bulk-archive-change/SKILL.md +246 -0
- package/.claude/skills/openspec-continue-change/SKILL.md +118 -0
- package/.claude/skills/openspec-explore/SKILL.md +290 -0
- package/.claude/skills/openspec-ff-change/SKILL.md +101 -0
- package/.claude/skills/openspec-new-change/SKILL.md +74 -0
- package/.claude/skills/openspec-onboard/SKILL.md +529 -0
- package/.claude/skills/openspec-sync-specs/SKILL.md +138 -0
- package/.claude/skills/openspec-verify-change/SKILL.md +168 -0
- package/.claude/skills/performance-doctor/SKILL.md +627 -0
- package/.claude/skills/project-navigator/SKILL.md +305 -0
- package/.claude/skills/redis-cache/SKILL.md +839 -0
- package/.claude/skills/scheduled-jobs/SKILL.md +633 -0
- package/.claude/skills/security-guard/SKILL.md +748 -0
- package/.claude/skills/sms-mail/SKILL.md +766 -0
- package/.claude/skills/social-login/SKILL.md +668 -0
- package/.claude/skills/store-pc/SKILL.md +366 -0
- package/.claude/skills/task-tracker/SKILL.md +307 -0
- package/.claude/skills/tech-decision/SKILL.md +393 -0
- package/.claude/skills/tenant-management/SKILL.md +603 -0
- package/.claude/skills/test-development/SKILL.md +755 -0
- package/.claude/skills/ui-pc/SKILL.md +438 -0
- package/.claude/skills/utils-toolkit/SKILL.md +615 -0
- package/.claude/skills/websocket-sse/SKILL.md +716 -0
- package/.claude/skills/workflow-engine/SKILL.md +676 -0
- package/.claude/templates//345/276/205/345/212/236/346/270/205/345/215/225/346/250/241/346/235/277.md +56 -0
- package/.claude/templates//351/234/200/346/261/202/346/226/207/346/241/243/346/250/241/346/235/277.md +85 -0
- package/.claude/templates//351/241/271/347/233/256/347/212/266/346/200/201/346/250/241/346/235/277.md +43 -0
- package/.codex/skills/add-skill/SKILL.md +352 -0
- package/.codex/skills/add-todo/SKILL.md +269 -0
- package/.codex/skills/api-development/SKILL.md +693 -0
- package/.codex/skills/architecture-design/SKILL.md +628 -0
- package/.codex/skills/backend-annotations/SKILL.md +664 -0
- package/.codex/skills/banana-image/CHANGELOG.md +37 -0
- package/.codex/skills/banana-image/README.md +146 -0
- package/.codex/skills/banana-image/SKILL.md +164 -0
- package/.codex/skills/banana-image/assets/logo.png +0 -0
- package/.codex/skills/banana-image/references/advanced-usage.md +189 -0
- package/.codex/skills/banana-image/scripts/apply_template.py +125 -0
- package/.codex/skills/banana-image/scripts/banana_image_exec.ts +412 -0
- package/.codex/skills/banana-image/scripts/batch_prep.py +82 -0
- package/.codex/skills/banana-image/scripts/package-lock.json +1437 -0
- package/.codex/skills/banana-image/scripts/package.json +18 -0
- package/.codex/skills/banana-image/scripts/requirements.txt +10 -0
- package/.codex/skills/banana-image/templates/poster.json +22 -0
- package/.codex/skills/banana-image/templates/product.json +17 -0
- package/.codex/skills/banana-image/templates/social.json +22 -0
- package/.codex/skills/banana-image/templates/thumbnail.json +17 -0
- package/.codex/skills/brainstorm/SKILL.md +648 -0
- package/.codex/skills/bug-detective/SKILL.md +1206 -0
- package/.codex/skills/check/SKILL.md +367 -0
- package/.codex/skills/code-patterns/SKILL.md +442 -0
- package/.codex/skills/collaborating-with-codex/SKILL.md +174 -0
- package/.codex/skills/collaborating-with-codex/scripts/codex_bridge.py +275 -0
- package/.codex/skills/collaborating-with-gemini/SKILL.md +194 -0
- package/.codex/skills/collaborating-with-gemini/scripts/gemini_bridge.py +275 -0
- package/.codex/skills/crud/SKILL.md +265 -0
- package/.codex/skills/crud-development/SKILL.md +637 -0
- package/.codex/skills/data-permission/SKILL.md +591 -0
- package/.codex/skills/database-ops/SKILL.md +553 -0
- package/.codex/skills/dev/SKILL.md +187 -0
- package/.codex/skills/error-handler/SKILL.md +361 -0
- package/.codex/skills/file-oss-management/SKILL.md +863 -0
- package/.codex/skills/git-workflow/SKILL.md +375 -0
- package/.codex/skills/init-docs/SKILL.md +194 -0
- package/.codex/skills/json-serialization/SKILL.md +357 -0
- package/.codex/skills/leniu-api-development/SKILL.md +803 -0
- package/.codex/skills/leniu-architecture-design/SKILL.md +594 -0
- package/.codex/skills/leniu-backend-annotations/SKILL.md +662 -0
- package/.codex/skills/leniu-code-patterns/SKILL.md +365 -0
- package/.codex/skills/leniu-crud-development/SKILL.md +1110 -0
- package/.codex/skills/leniu-data-permission/SKILL.md +256 -0
- package/.codex/skills/leniu-database-ops/SKILL.md +426 -0
- package/.codex/skills/leniu-error-handler/SKILL.md +462 -0
- package/.codex/skills/leniu-java-amount-handling/SKILL.md +461 -0
- package/.codex/skills/leniu-java-code-style/SKILL.md +510 -0
- package/.codex/skills/leniu-java-concurrent/SKILL.md +400 -0
- package/.codex/skills/leniu-java-entity/SKILL.md +751 -0
- package/.codex/skills/leniu-java-export/SKILL.md +560 -0
- package/.codex/skills/leniu-java-logging/SKILL.md +832 -0
- package/.codex/skills/leniu-java-mq/SKILL.md +338 -0
- package/.codex/skills/leniu-java-mybatis/SKILL.md +640 -0
- package/.codex/skills/leniu-java-report-query-param/SKILL.md +291 -0
- package/.codex/skills/leniu-java-task/SKILL.md +367 -0
- package/.codex/skills/leniu-java-total-line/SKILL.md +195 -0
- package/.codex/skills/leniu-marketing-price-rule-customizer/SKILL.md +301 -0
- package/.codex/skills/leniu-marketing-recharge-rule-customizer/SKILL.md +285 -0
- package/.codex/skills/leniu-mealtime/SKILL.md +215 -0
- package/.codex/skills/leniu-redis-cache/SKILL.md +316 -0
- package/.codex/skills/leniu-security-guard/SKILL.md +520 -0
- package/.codex/skills/leniu-utils-toolkit/SKILL.md +378 -0
- package/.codex/skills/next/SKILL.md +137 -0
- package/.codex/skills/openspec-apply-change/SKILL.md +156 -0
- package/.codex/skills/openspec-archive-change/SKILL.md +114 -0
- package/.codex/skills/openspec-bulk-archive-change/SKILL.md +246 -0
- package/.codex/skills/openspec-continue-change/SKILL.md +118 -0
- package/.codex/skills/openspec-explore/SKILL.md +290 -0
- package/.codex/skills/openspec-ff-change/SKILL.md +101 -0
- package/.codex/skills/openspec-new-change/SKILL.md +74 -0
- package/.codex/skills/openspec-onboard/SKILL.md +529 -0
- package/.codex/skills/openspec-sync-specs/SKILL.md +138 -0
- package/.codex/skills/openspec-verify-change/SKILL.md +168 -0
- package/.codex/skills/performance-doctor/SKILL.md +627 -0
- package/.codex/skills/progress/SKILL.md +193 -0
- package/.codex/skills/project-navigator/SKILL.md +286 -0
- package/.codex/skills/redis-cache/SKILL.md +829 -0
- package/.codex/skills/scheduled-jobs/SKILL.md +633 -0
- package/.codex/skills/security-guard/SKILL.md +739 -0
- package/.codex/skills/sms-mail/SKILL.md +766 -0
- package/.codex/skills/social-login/SKILL.md +668 -0
- package/.codex/skills/start/SKILL.md +154 -0
- package/.codex/skills/store-pc/SKILL.md +491 -0
- package/.codex/skills/sync/SKILL.md +149 -0
- package/.codex/skills/task-tracker/SKILL.md +307 -0
- package/.codex/skills/tech-decision/SKILL.md +393 -0
- package/.codex/skills/tenant-management/SKILL.md +603 -0
- package/.codex/skills/test-development/SKILL.md +755 -0
- package/.codex/skills/ui-pc/SKILL.md +475 -0
- package/.codex/skills/update-status/SKILL.md +159 -0
- package/.codex/skills/utils-toolkit/SKILL.md +593 -0
- package/.codex/skills/websocket-sse/SKILL.md +716 -0
- package/.codex/skills/workflow-engine/SKILL.md +676 -0
- package/.cursor/agents/code-reviewer.md +139 -0
- package/.cursor/agents/project-manager.md +159 -0
- package/.cursor/commands/opsx-apply.md +152 -0
- package/.cursor/commands/opsx-archive.md +157 -0
- package/.cursor/commands/opsx-bulk-archive.md +242 -0
- package/.cursor/commands/opsx-continue.md +114 -0
- package/.cursor/commands/opsx-explore.md +174 -0
- package/.cursor/commands/opsx-ff.md +94 -0
- package/.cursor/commands/opsx-new.md +69 -0
- package/.cursor/commands/opsx-onboard.md +525 -0
- package/.cursor/commands/opsx-sync.md +134 -0
- package/.cursor/commands/opsx-verify.md +164 -0
- package/.cursor/mcp.json +22 -0
- package/.cursor/skills/add-skill/SKILL.md +352 -0
- package/.cursor/skills/api-development/SKILL.md +560 -0
- package/.cursor/skills/architecture-design/SKILL.md +756 -0
- package/.cursor/skills/backend-annotations/SKILL.md +674 -0
- package/.cursor/skills/banana-image/CHANGELOG.md +37 -0
- package/.cursor/skills/banana-image/README.md +146 -0
- package/.cursor/skills/banana-image/SKILL.md +164 -0
- package/.cursor/skills/banana-image/assets/logo.png +0 -0
- package/.cursor/skills/banana-image/references/advanced-usage.md +189 -0
- package/.cursor/skills/banana-image/scripts/apply_template.py +125 -0
- package/.cursor/skills/banana-image/scripts/banana_image_exec.ts +412 -0
- package/.cursor/skills/banana-image/scripts/batch_prep.py +82 -0
- package/.cursor/skills/banana-image/scripts/package-lock.json +1437 -0
- package/.cursor/skills/banana-image/scripts/package.json +18 -0
- package/.cursor/skills/banana-image/scripts/requirements.txt +10 -0
- package/.cursor/skills/banana-image/templates/poster.json +22 -0
- package/.cursor/skills/banana-image/templates/product.json +17 -0
- package/.cursor/skills/banana-image/templates/social.json +22 -0
- package/.cursor/skills/banana-image/templates/thumbnail.json +17 -0
- package/.cursor/skills/brainstorm/SKILL.md +648 -0
- package/.cursor/skills/bug-detective/SKILL.md +1206 -0
- package/.cursor/skills/code-patterns/SKILL.md +590 -0
- package/.cursor/skills/collaborating-with-codex/SKILL.md +174 -0
- package/.cursor/skills/collaborating-with-codex/scripts/codex_bridge.py +275 -0
- package/.cursor/skills/collaborating-with-gemini/SKILL.md +194 -0
- package/.cursor/skills/collaborating-with-gemini/scripts/gemini_bridge.py +275 -0
- package/.cursor/skills/crud-development/SKILL.md +649 -0
- package/.cursor/skills/data-permission/SKILL.md +599 -0
- package/.cursor/skills/database-ops/SKILL.md +407 -0
- package/.cursor/skills/error-handler/SKILL.md +371 -0
- package/.cursor/skills/file-oss-management/SKILL.md +863 -0
- package/.cursor/skills/git-workflow/SKILL.md +375 -0
- package/.cursor/skills/json-serialization/SKILL.md +357 -0
- package/.cursor/skills/leniu-api-development/SKILL.md +803 -0
- package/.cursor/skills/leniu-architecture-design/SKILL.md +598 -0
- package/.cursor/skills/leniu-backend-annotations/SKILL.md +664 -0
- package/.cursor/skills/leniu-code-patterns/SKILL.md +365 -0
- package/.cursor/skills/leniu-crud-development/SKILL.md +1110 -0
- package/.cursor/skills/leniu-data-permission/SKILL.md +256 -0
- package/.cursor/skills/leniu-database-ops/SKILL.md +426 -0
- package/.cursor/skills/leniu-error-handler/SKILL.md +462 -0
- package/.cursor/skills/leniu-java-amount-handling/SKILL.md +461 -0
- package/.cursor/skills/leniu-java-code-style/SKILL.md +510 -0
- package/.cursor/skills/leniu-java-concurrent/SKILL.md +400 -0
- package/.cursor/skills/leniu-java-entity/SKILL.md +751 -0
- package/.cursor/skills/leniu-java-export/SKILL.md +560 -0
- package/.cursor/skills/leniu-java-logging/SKILL.md +832 -0
- package/.cursor/skills/leniu-java-mq/SKILL.md +338 -0
- package/.cursor/skills/leniu-java-mybatis/SKILL.md +640 -0
- package/.cursor/skills/leniu-java-report-query-param/SKILL.md +291 -0
- package/.cursor/skills/leniu-java-task/SKILL.md +367 -0
- package/.cursor/skills/leniu-java-total-line/SKILL.md +195 -0
- package/.cursor/skills/leniu-marketing-price-rule-customizer/SKILL.md +301 -0
- package/.cursor/skills/leniu-marketing-recharge-rule-customizer/SKILL.md +285 -0
- package/.cursor/skills/leniu-mealtime/SKILL.md +215 -0
- package/.cursor/skills/leniu-redis-cache/SKILL.md +316 -0
- package/.cursor/skills/leniu-security-guard/SKILL.md +520 -0
- package/.cursor/skills/leniu-utils-toolkit/SKILL.md +380 -0
- package/.cursor/skills/openspec-apply-change/SKILL.md +156 -0
- package/.cursor/skills/openspec-archive-change/SKILL.md +114 -0
- package/.cursor/skills/openspec-bulk-archive-change/SKILL.md +246 -0
- package/.cursor/skills/openspec-continue-change/SKILL.md +118 -0
- package/.cursor/skills/openspec-explore/SKILL.md +290 -0
- package/.cursor/skills/openspec-ff-change/SKILL.md +101 -0
- package/.cursor/skills/openspec-new-change/SKILL.md +74 -0
- package/.cursor/skills/openspec-onboard/SKILL.md +529 -0
- package/.cursor/skills/openspec-sync-specs/SKILL.md +138 -0
- package/.cursor/skills/openspec-verify-change/SKILL.md +168 -0
- package/.cursor/skills/performance-doctor/SKILL.md +627 -0
- package/.cursor/skills/project-navigator/SKILL.md +305 -0
- package/.cursor/skills/redis-cache/SKILL.md +839 -0
- package/.cursor/skills/scheduled-jobs/SKILL.md +633 -0
- package/.cursor/skills/security-guard/SKILL.md +748 -0
- package/.cursor/skills/sms-mail/SKILL.md +766 -0
- package/.cursor/skills/social-login/SKILL.md +668 -0
- package/.cursor/skills/store-pc/SKILL.md +366 -0
- package/.cursor/skills/task-tracker/SKILL.md +307 -0
- package/.cursor/skills/tech-decision/SKILL.md +393 -0
- package/.cursor/skills/tenant-management/SKILL.md +603 -0
- package/.cursor/skills/test-development/SKILL.md +755 -0
- package/.cursor/skills/ui-pc/SKILL.md +438 -0
- package/.cursor/skills/utils-toolkit/SKILL.md +615 -0
- package/.cursor/skills/websocket-sse/SKILL.md +716 -0
- package/.cursor/skills/workflow-engine/SKILL.md +676 -0
- package/AGENTS.md +669 -0
- package/CLAUDE.md +205 -0
- package/README.md +205 -0
- package/bin/index.js +179 -0
- package/init.sh +178 -0
- package/package.json +27 -0
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: leniu-security-guard
|
|
3
|
+
description: |
|
|
4
|
+
leniu-tengyun-core / leniu-yunshitang 项目安全权限控制规范。包含认证注解、SQL注入防护、XSS防护、数据脱敏、限流防重放。
|
|
5
|
+
|
|
6
|
+
触发场景:
|
|
7
|
+
- 配置接口认证注解(@RequiresAuthentication/@RequiresGuest)
|
|
8
|
+
- 防 SQL 注入(#{} 参数化查询)
|
|
9
|
+
- XSS/CSRF 防护
|
|
10
|
+
- 数据脱敏(密码、手机号)
|
|
11
|
+
- 限流和防重放攻击
|
|
12
|
+
|
|
13
|
+
适用项目:
|
|
14
|
+
- leniu-tengyun-core:/Users/xujiajun/Developer/gongsi_proj/leniu-api/leniu-tengyun-core
|
|
15
|
+
- leniu-yunshitang:/Users/xujiajun/Developer/gongsi_proj/leniu-api/leniu-tengyun/leniu-yunshitang
|
|
16
|
+
|
|
17
|
+
触发词:leniu-安全、leniu-认证、leniu-@RequiresAuthentication、leniu-@RequiresGuest、leniu-SQL注入、leniu-XSS、leniu-数据脱敏、leniu-限流、net.xnzn、leniu-yunshitang
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
# leniu-security-guard
|
|
21
|
+
|
|
22
|
+
适用于 leniu-tengyun-core / leniu-yunshitang 项目的安全权限控制。
|
|
23
|
+
|
|
24
|
+
## 认证注解
|
|
25
|
+
|
|
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` |
|
|
34
|
+
|
|
35
|
+
## 基础用法
|
|
36
|
+
|
|
37
|
+
### Controller 认证
|
|
38
|
+
|
|
39
|
+
```java
|
|
40
|
+
import net.xnzn.framework.secure.filter.annotation.RequiresAuthentication;
|
|
41
|
+
import net.xnzn.framework.secure.filter.annotation.RequiresGuest;
|
|
42
|
+
|
|
43
|
+
// 需要登录认证
|
|
44
|
+
@RestController
|
|
45
|
+
@RequestMapping("/api/v2/xxx")
|
|
46
|
+
@RequiresAuthentication
|
|
47
|
+
public class XxxController {
|
|
48
|
+
// ...
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// 允许游客访问(无需登录)
|
|
52
|
+
@GetMapping("/public/info")
|
|
53
|
+
@RequiresGuest
|
|
54
|
+
public LeResponse<String> getPublicInfo() {
|
|
55
|
+
return LeResponse.succ("public data");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// 需要特定权限
|
|
59
|
+
@GetMapping("/admin/users")
|
|
60
|
+
@RequiresPermissions("system:user:list")
|
|
61
|
+
public LeResponse<List<User>> listUsers() {
|
|
62
|
+
return LeResponse.succ(userService.list());
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 需要所有指定权限(AND 逻辑,默认)
|
|
66
|
+
@RequiresPermissions(value = {"system:user:add", "system:user:edit"}, logical = Logical.AND)
|
|
67
|
+
public LeResponse<Void> addUser(User user) { }
|
|
68
|
+
|
|
69
|
+
// 需要任一权限(OR 逻辑)
|
|
70
|
+
@RequiresPermissions(value = {"system:user:add", "system:user:edit"}, logical = Logical.OR)
|
|
71
|
+
public LeResponse<Void> editUser(User user) { }
|
|
72
|
+
|
|
73
|
+
// 需要指定角色
|
|
74
|
+
@RequiresRoles("admin")
|
|
75
|
+
public LeResponse<Void> adminAction() { }
|
|
76
|
+
|
|
77
|
+
// 需要所有角色
|
|
78
|
+
@RequiresRoles(value = {"admin", "manager"}, logical = Logical.AND)
|
|
79
|
+
public LeResponse<Void> superAction() { }
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Service 层获取用户信息
|
|
83
|
+
|
|
84
|
+
```java
|
|
85
|
+
import net.xnzn.framework.secure.token.TokenManager;
|
|
86
|
+
|
|
87
|
+
// 检查是否登录
|
|
88
|
+
if (TokenManager.isLogin()) {
|
|
89
|
+
// 已登录
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 获取用户 ID
|
|
93
|
+
Long userId = TokenManager.getSubjectId().orElse(null);
|
|
94
|
+
|
|
95
|
+
// 获取用户名
|
|
96
|
+
String userName = TokenManager.getSubjectName().orElse(null);
|
|
97
|
+
|
|
98
|
+
// 获取附加数据
|
|
99
|
+
Map<String, String> userData = TokenManager.getSubjectData();
|
|
100
|
+
String orgId = userData.get("orgId");
|
|
101
|
+
|
|
102
|
+
// 检查权限
|
|
103
|
+
if (TokenManager.hasPermission("system:user:add")) {
|
|
104
|
+
// 有权限
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// 检查多个权限(AND)
|
|
108
|
+
if (TokenManager.hasPermission("system:user:add", "system:user:edit")) {
|
|
109
|
+
// 拥有所有权限
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// 检查任一权限(OR)
|
|
113
|
+
if (TokenManager.hasAnyPermission("system:user:add", "system:user:edit")) {
|
|
114
|
+
// 拥有任一权限
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// 检查角色
|
|
118
|
+
if (TokenManager.hasRole("admin")) {
|
|
119
|
+
// 是管理员
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// 检查任一角色
|
|
123
|
+
if (TokenManager.hasAnyRole("admin", "manager")) {
|
|
124
|
+
// 是管理员或经理
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### 附加用户数据
|
|
129
|
+
|
|
130
|
+
```java
|
|
131
|
+
// 添加附加数据到 Token
|
|
132
|
+
TokenManager.attachData("orgId", "12345");
|
|
133
|
+
TokenManager.attachData("deptId", "67890");
|
|
134
|
+
|
|
135
|
+
// 批量添加
|
|
136
|
+
Map<String, String> data = new HashMap<>();
|
|
137
|
+
data.put("orgId", "12345");
|
|
138
|
+
data.put("deptId", "67890");
|
|
139
|
+
TokenManager.attachData(data);
|
|
140
|
+
|
|
141
|
+
// 获取附加数据
|
|
142
|
+
Map<String, String> userData = TokenManager.getSubjectData();
|
|
143
|
+
String orgId = userData.get("orgId");
|
|
144
|
+
|
|
145
|
+
// 移除附加数据
|
|
146
|
+
TokenManager.removeData("orgId", "deptId");
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### 登出操作
|
|
150
|
+
|
|
151
|
+
```java
|
|
152
|
+
// 登出当前用户
|
|
153
|
+
TokenManager.logout();
|
|
154
|
+
|
|
155
|
+
// 撤销认证(强制下线)
|
|
156
|
+
TokenManager.revokeAuthenticate();
|
|
157
|
+
|
|
158
|
+
// 撤销指定用户的旧 Token(保留最近 N 个)
|
|
159
|
+
TokenManager.revokeAuthenticate(userId, 3);
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### 权限缓存管理
|
|
163
|
+
|
|
164
|
+
```java
|
|
165
|
+
// 清除用户权限缓存
|
|
166
|
+
TokenManager.clearPermission(userId);
|
|
167
|
+
|
|
168
|
+
// 清除用户角色缓存
|
|
169
|
+
TokenManager.clearRole(userId);
|
|
170
|
+
|
|
171
|
+
// 清除用户权限和角色缓存
|
|
172
|
+
TokenManager.clearRoleAndPermission(userId);
|
|
173
|
+
|
|
174
|
+
// 清除所有权限缓存
|
|
175
|
+
TokenManager.clearAllRoleAndPermission();
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## WebContext 使用
|
|
179
|
+
|
|
180
|
+
```java
|
|
181
|
+
import net.xnzn.framework.secure.WebContext;
|
|
182
|
+
|
|
183
|
+
// 获取当前请求
|
|
184
|
+
HttpServletRequest request = WebContext.get().getRequest().orElse(null);
|
|
185
|
+
|
|
186
|
+
// 获取当前响应
|
|
187
|
+
HttpServletResponse response = WebContext.get().getResponse().orElse(null);
|
|
188
|
+
|
|
189
|
+
// 获取 AccessToken
|
|
190
|
+
Optional<AccessToken> token = WebContext.get().getAccessToken();
|
|
191
|
+
|
|
192
|
+
// 设置/获取属性
|
|
193
|
+
WebContext.get().setAttribute("customKey", "customValue");
|
|
194
|
+
Object value = WebContext.get().getAttribute("customKey");
|
|
195
|
+
|
|
196
|
+
// 清除上下文
|
|
197
|
+
WebContext.reset();
|
|
198
|
+
```
|
|
199
|
+
|
|
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
|
+
```
|
|
261
|
+
|
|
262
|
+
## 数据权限校验(防越权)
|
|
263
|
+
|
|
264
|
+
```java
|
|
265
|
+
@Transactional(rollbackFor = Exception.class)
|
|
266
|
+
public void delete(Long id) {
|
|
267
|
+
// 查询数据
|
|
268
|
+
Order order = orderMapper.selectById(id);
|
|
269
|
+
Assert.notNull(order, () -> new LeException("订单不存在"));
|
|
270
|
+
|
|
271
|
+
// 校验数据归属
|
|
272
|
+
Long currentUserId = TokenManager.getSubjectId().orElseThrow(
|
|
273
|
+
() -> new LeException("用户未登录")
|
|
274
|
+
);
|
|
275
|
+
if (!order.getUserId().equals(currentUserId)) {
|
|
276
|
+
throw new LeException("无权操作该订单");
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// 执行删除
|
|
280
|
+
orderMapper.deleteById(id);
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## 数据脱敏
|
|
285
|
+
|
|
286
|
+
### 日志脱敏
|
|
287
|
+
|
|
288
|
+
```java
|
|
289
|
+
// ❌ 错误:记录敏感信息
|
|
290
|
+
log.info("用户登录,username:{}, password:{}", username, password);
|
|
291
|
+
|
|
292
|
+
// ✅ 正确:不记录敏感信息
|
|
293
|
+
log.info("用户登录,username:{}", username);
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### 手机号 / 身份证 / 银行卡脱敏
|
|
297
|
+
|
|
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
|
+
}
|
|
306
|
+
|
|
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
|
+
}
|
|
314
|
+
|
|
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
|
+
}
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### VO 中敏感字段处理
|
|
325
|
+
|
|
326
|
+
```java
|
|
327
|
+
@Data
|
|
328
|
+
public class UserVO {
|
|
329
|
+
// 密码绝不返回
|
|
330
|
+
@JsonIgnore
|
|
331
|
+
private String password;
|
|
332
|
+
|
|
333
|
+
// 手机号脱敏
|
|
334
|
+
@JsonSerialize(using = MobileSerializer.class)
|
|
335
|
+
private String mobile;
|
|
336
|
+
|
|
337
|
+
// 身份证脱敏
|
|
338
|
+
@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
|
+
}
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
## 防重放攻击
|
|
370
|
+
|
|
371
|
+
```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);
|
|
395
|
+
|
|
396
|
+
// 5. 处理业务
|
|
397
|
+
doProcess(request);
|
|
398
|
+
}
|
|
399
|
+
```
|
|
400
|
+
|
|
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
|
+
```
|
|
414
|
+
|
|
415
|
+
## 输入验证
|
|
416
|
+
|
|
417
|
+
```java
|
|
418
|
+
@Data
|
|
419
|
+
public class UserParam {
|
|
420
|
+
@NotBlank(message = "用户名不能为空")
|
|
421
|
+
@Pattern(regexp = "^[a-zA-Z0-9_]{4,20}$", message = "用户名格式不正确")
|
|
422
|
+
private String username;
|
|
423
|
+
|
|
424
|
+
@NotBlank(message = "密码不能为空")
|
|
425
|
+
@Size(min = 6, max = 20, message = "密码长度必须在6-20之间")
|
|
426
|
+
private String password;
|
|
427
|
+
|
|
428
|
+
@NotBlank(message = "手机号不能为空")
|
|
429
|
+
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
|
|
430
|
+
private String mobile;
|
|
431
|
+
|
|
432
|
+
@Email(message = "邮箱格式不正确")
|
|
433
|
+
private String email;
|
|
434
|
+
}
|
|
435
|
+
```
|
|
436
|
+
|
|
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
|
+
```
|
|
472
|
+
|
|
473
|
+
## 最小权限原则
|
|
474
|
+
|
|
475
|
+
```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);
|
|
485
|
+
}
|
|
486
|
+
```
|
|
487
|
+
|
|
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()` |
|
|
511
|
+
|
|
512
|
+
## 注意事项
|
|
513
|
+
|
|
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}`
|