aigroup-workflow 2.2.1 → 2.2.2
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/commands/fix-build.md +10 -5
- package/.claude/commands/init-project.md +13 -8
- package/.claude/commands/plan.md +15 -8
- package/.claude/commands/review.md +12 -6
- package/.claude/commands/tdd.md +11 -5
- package/.claude/commands/workflow-start.md +20 -11
- package/.claude/settings.json +28 -0
- package/.codex/agents/architect.toml +207 -0
- package/.codex/agents/build-error-resolver.toml +110 -0
- package/.codex/agents/code-reviewer.toml +233 -0
- package/.codex/agents/doc-updater.toml +103 -0
- package/.codex/agents/e2e-runner.toml +103 -0
- package/.codex/agents/get-current-datetime.toml +23 -0
- package/.codex/agents/init-architect.toml +181 -0
- package/.codex/agents/planner.toml +208 -0
- package/.codex/agents/refactor-cleaner.toml +81 -0
- package/.codex/agents/rust-reviewer.toml +90 -0
- package/.codex/agents/security-reviewer.toml +104 -0
- package/.codex/agents/tdd-guide.toml +87 -0
- package/AGENTS.md +2 -2
- package/CLAUDE.md +23 -1
- package/LICENSE +20 -20
- package/README.md +333 -333
- package/agents/a11y-architect.md +141 -141
- package/agents/architect.md +211 -211
- package/agents/build-error-resolver.md +114 -114
- package/agents/chief-of-staff.md +151 -151
- package/agents/code-architect.md +71 -71
- package/agents/code-explorer.md +69 -69
- package/agents/code-reviewer.md +237 -237
- package/agents/code-simplifier.md +47 -47
- package/agents/comment-analyzer.md +45 -45
- package/agents/conversation-analyzer.md +52 -52
- package/agents/cpp-build-resolver.md +90 -90
- package/agents/cpp-reviewer.md +72 -72
- package/agents/csharp-reviewer.md +101 -101
- package/agents/dart-build-resolver.md +201 -201
- package/agents/database-reviewer.md +91 -91
- package/agents/doc-updater.md +107 -107
- package/agents/docs-lookup.md +68 -68
- package/agents/e2e-runner.md +107 -107
- package/agents/flutter-reviewer.md +243 -243
- package/agents/gan-evaluator.md +209 -209
- package/agents/gan-generator.md +131 -131
- package/agents/gan-planner.md +99 -99
- package/agents/get-current-datetime.md +26 -26
- package/agents/go-build-resolver.md +94 -94
- package/agents/go-reviewer.md +76 -76
- package/agents/harness-optimizer.md +35 -35
- package/agents/healthcare-reviewer.md +83 -83
- package/agents/java-build-resolver.md +153 -153
- package/agents/java-reviewer.md +92 -92
- package/agents/kotlin-build-resolver.md +118 -118
- package/agents/kotlin-reviewer.md +159 -159
- package/agents/loop-operator.md +36 -36
- package/agents/opensource-forker.md +198 -198
- package/agents/opensource-packager.md +249 -249
- package/agents/opensource-sanitizer.md +188 -188
- package/agents/performance-optimizer.md +446 -446
- package/agents/planner.md +212 -212
- package/agents/pr-test-analyzer.md +45 -45
- package/agents/python-reviewer.md +98 -98
- package/agents/pytorch-build-resolver.md +120 -120
- package/agents/refactor-cleaner.md +85 -85
- package/agents/rust-build-resolver.md +148 -148
- package/agents/rust-reviewer.md +94 -94
- package/agents/security-reviewer.md +108 -108
- package/agents/seo-specialist.md +59 -59
- package/agents/silent-failure-hunter.md +50 -50
- package/agents/tdd-guide.md +91 -91
- package/agents/type-design-analyzer.md +41 -41
- package/agents/typescript-reviewer.md +112 -112
- package/cli/commands/update.mjs +1 -1
- package/cli/utils/scaffold.mjs +53 -0
- package/docs/rules/agents.md +166 -50
- package/docs/rules/cpp/coding-style.md +44 -44
- package/docs/rules/cpp/hooks.md +39 -39
- package/docs/rules/cpp/patterns.md +51 -51
- package/docs/rules/cpp/security.md +51 -51
- package/docs/rules/cpp/testing.md +44 -44
- package/docs/rules/csharp/coding-style.md +72 -72
- package/docs/rules/csharp/hooks.md +25 -25
- package/docs/rules/csharp/patterns.md +50 -50
- package/docs/rules/csharp/security.md +58 -58
- package/docs/rules/csharp/testing.md +46 -46
- package/docs/rules/dart/coding-style.md +159 -159
- package/docs/rules/dart/hooks.md +66 -66
- package/docs/rules/dart/patterns.md +261 -261
- package/docs/rules/dart/security.md +135 -135
- package/docs/rules/dart/testing.md +215 -215
- package/docs/rules/golang/coding-style.md +32 -32
- package/docs/rules/golang/hooks.md +17 -17
- package/docs/rules/golang/patterns.md +45 -45
- package/docs/rules/golang/security.md +34 -34
- package/docs/rules/golang/testing.md +31 -31
- package/docs/rules/java/coding-style.md +114 -114
- package/docs/rules/java/hooks.md +18 -18
- package/docs/rules/java/patterns.md +146 -146
- package/docs/rules/java/security.md +100 -100
- package/docs/rules/java/testing.md +131 -131
- package/docs/rules/kotlin/coding-style.md +86 -86
- package/docs/rules/kotlin/hooks.md +17 -17
- package/docs/rules/kotlin/patterns.md +146 -146
- package/docs/rules/kotlin/security.md +82 -82
- package/docs/rules/kotlin/testing.md +128 -128
- package/docs/rules/perl/coding-style.md +46 -46
- package/docs/rules/perl/hooks.md +22 -22
- package/docs/rules/perl/patterns.md +76 -76
- package/docs/rules/perl/security.md +69 -69
- package/docs/rules/perl/testing.md +54 -54
- package/docs/rules/php/coding-style.md +40 -40
- package/docs/rules/php/hooks.md +24 -24
- package/docs/rules/php/patterns.md +33 -33
- package/docs/rules/php/security.md +37 -37
- package/docs/rules/php/testing.md +39 -39
- package/docs/rules/python/coding-style.md +42 -42
- package/docs/rules/python/hooks.md +19 -19
- package/docs/rules/python/patterns.md +39 -39
- package/docs/rules/python/security.md +30 -30
- package/docs/rules/python/testing.md +38 -38
- package/docs/rules/rust/coding-style.md +151 -151
- package/docs/rules/rust/hooks.md +16 -16
- package/docs/rules/rust/patterns.md +168 -168
- package/docs/rules/rust/security.md +141 -141
- package/docs/rules/rust/testing.md +154 -154
- package/docs/rules/swift/coding-style.md +47 -47
- package/docs/rules/swift/hooks.md +20 -20
- package/docs/rules/swift/patterns.md +66 -66
- package/docs/rules/swift/security.md +33 -33
- package/docs/rules/swift/testing.md +45 -45
- package/docs/rules/typescript/coding-style.md +199 -199
- package/docs/rules/typescript/hooks.md +22 -22
- package/docs/rules/typescript/patterns.md +52 -52
- package/docs/rules/typescript/security.md +28 -28
- package/docs/rules/typescript/testing.md +18 -18
- package/docs/rules/web/coding-style.md +96 -96
- package/docs/rules/web/design-quality.md +62 -62
- package/docs/rules/web/hooks.md +120 -120
- package/docs/rules/web/patterns.md +79 -79
- package/docs/rules/web/performance.md +64 -64
- package/docs/rules/web/security.md +57 -57
- package/docs/rules/web/testing.md +55 -55
- package/docs/templates/README.md +36 -36
- package/docs/templates/ai-project-final.md +124 -124
- package/docs/templates/ai-project.md +105 -105
- package/docs/templates/api.md +157 -157
- package/docs/templates/bug.md +62 -62
- package/docs/templates/code-review.md +87 -87
- package/docs/templates/generic.md +116 -116
- package/docs/templates/implementation-plan.md +1 -1
- package/docs/templates/meeting.md +68 -68
- package/docs/templates/prd.md +98 -98
- package/docs/templates/ui.md +134 -134
- package/docs/workflow-pipeline.md +5 -5
- package/package.json +40 -39
- package/skills/SUPERPOWERS-LICENSE +21 -21
- package/skills/ai-ml/fine-tuning-expert/SKILL.md +162 -162
- package/skills/ai-ml/fine-tuning-expert/references/dataset-preparation.md +540 -540
- package/skills/ai-ml/fine-tuning-expert/references/deployment-optimization.md +673 -673
- package/skills/ai-ml/fine-tuning-expert/references/evaluation-metrics.md +597 -597
- package/skills/ai-ml/fine-tuning-expert/references/hyperparameter-tuning.md +565 -565
- package/skills/ai-ml/fine-tuning-expert/references/lora-peft.md +347 -347
- package/skills/ai-ml/ml-pipeline/SKILL.md +159 -159
- package/skills/ai-ml/ml-pipeline/references/experiment-tracking.md +833 -833
- package/skills/ai-ml/ml-pipeline/references/feature-engineering.md +631 -631
- package/skills/ai-ml/ml-pipeline/references/model-validation.md +978 -978
- package/skills/ai-ml/ml-pipeline/references/pipeline-orchestration.md +907 -907
- package/skills/ai-ml/ml-pipeline/references/training-pipelines.md +782 -782
- package/skills/ai-ml/rag-architect/SKILL.md +194 -194
- package/skills/ai-ml/rag-architect/references/chunking-strategies.md +878 -878
- package/skills/ai-ml/rag-architect/references/embedding-models.md +561 -561
- package/skills/ai-ml/rag-architect/references/rag-evaluation.md +833 -833
- package/skills/ai-ml/rag-architect/references/retrieval-optimization.md +795 -795
- package/skills/ai-ml/rag-architect/references/vector-databases.md +589 -589
- package/skills/ai-ml/spark-engineer/SKILL.md +148 -148
- package/skills/ai-ml/spark-engineer/references/partitioning-caching.md +543 -543
- package/skills/ai-ml/spark-engineer/references/performance-tuning.md +544 -544
- package/skills/ai-ml/spark-engineer/references/rdd-operations.md +599 -599
- package/skills/ai-ml/spark-engineer/references/spark-sql-dataframes.md +474 -474
- package/skills/ai-ml/spark-engineer/references/streaming-patterns.md +786 -786
- package/skills/backend/api-designer/SKILL.md +217 -217
- package/skills/backend/api-designer/references/error-handling.md +541 -541
- package/skills/backend/api-designer/references/openapi.md +824 -824
- package/skills/backend/api-designer/references/pagination.md +494 -494
- package/skills/backend/api-designer/references/rest-patterns.md +335 -335
- package/skills/backend/api-designer/references/versioning.md +391 -391
- package/skills/backend/architecture-designer/SKILL.md +117 -117
- package/skills/backend/architecture-designer/references/adr-template.md +116 -116
- package/skills/backend/architecture-designer/references/architecture-patterns.md +111 -111
- package/skills/backend/architecture-designer/references/database-selection.md +102 -102
- package/skills/backend/architecture-designer/references/nfr-checklist.md +112 -112
- package/skills/backend/architecture-designer/references/system-design.md +100 -100
- package/skills/backend/code-documenter/SKILL.md +147 -147
- package/skills/backend/code-documenter/references/api-docs-fastapi-django.md +166 -166
- package/skills/backend/code-documenter/references/api-docs-nestjs-express.md +220 -220
- package/skills/backend/code-documenter/references/coverage-reports.md +125 -125
- package/skills/backend/code-documenter/references/documentation-systems.md +333 -333
- package/skills/backend/code-documenter/references/interactive-api-docs.md +531 -531
- package/skills/backend/code-documenter/references/python-docstrings.md +121 -121
- package/skills/backend/code-documenter/references/typescript-jsdoc.md +145 -145
- package/skills/backend/code-documenter/references/user-guides-tutorials.md +530 -530
- package/skills/backend/debugging-wizard/SKILL.md +105 -105
- package/skills/backend/debugging-wizard/references/common-patterns.md +132 -132
- package/skills/backend/debugging-wizard/references/debugging-tools.md +140 -140
- package/skills/backend/debugging-wizard/references/quick-fixes.md +177 -177
- package/skills/backend/debugging-wizard/references/strategies.md +142 -142
- package/skills/backend/debugging-wizard/references/systematic-debugging.md +367 -367
- package/skills/backend/feature-forge/SKILL.md +98 -98
- package/skills/backend/feature-forge/references/acceptance-criteria.md +104 -104
- package/skills/backend/feature-forge/references/ears-syntax.md +99 -99
- package/skills/backend/feature-forge/references/interview-questions.md +150 -150
- package/skills/backend/feature-forge/references/pre-discovery-subagents.md +54 -54
- package/skills/backend/feature-forge/references/specification-template.md +103 -103
- package/skills/backend/fullstack-guardian/SKILL.md +105 -105
- package/skills/backend/fullstack-guardian/references/api-design-standards.md +307 -307
- package/skills/backend/fullstack-guardian/references/architecture-decisions.md +350 -350
- package/skills/backend/fullstack-guardian/references/backend-patterns.md +237 -237
- package/skills/backend/fullstack-guardian/references/common-patterns.md +134 -134
- package/skills/backend/fullstack-guardian/references/deliverables-checklist.md +354 -354
- package/skills/backend/fullstack-guardian/references/design-template.md +91 -91
- package/skills/backend/fullstack-guardian/references/error-handling.md +135 -135
- package/skills/backend/fullstack-guardian/references/frontend-patterns.md +340 -340
- package/skills/backend/fullstack-guardian/references/integration-patterns.md +333 -333
- package/skills/backend/fullstack-guardian/references/security-checklist.md +106 -106
- package/skills/backend/graphql-architect/SKILL.md +146 -146
- package/skills/backend/graphql-architect/references/federation.md +418 -418
- package/skills/backend/graphql-architect/references/migration-from-rest.md +1141 -1141
- package/skills/backend/graphql-architect/references/resolvers.md +425 -425
- package/skills/backend/graphql-architect/references/schema-design.md +393 -393
- package/skills/backend/graphql-architect/references/security.md +569 -569
- package/skills/backend/graphql-architect/references/subscriptions.md +510 -510
- package/skills/backend/legacy-modernizer/SKILL.md +137 -137
- package/skills/backend/legacy-modernizer/references/legacy-testing.md +381 -381
- package/skills/backend/legacy-modernizer/references/migration-strategies.md +423 -423
- package/skills/backend/legacy-modernizer/references/refactoring-patterns.md +395 -395
- package/skills/backend/legacy-modernizer/references/strangler-fig-pattern.md +281 -281
- package/skills/backend/legacy-modernizer/references/system-assessment.md +487 -487
- package/skills/backend/microservices-architect/SKILL.md +164 -164
- package/skills/backend/microservices-architect/references/communication.md +499 -499
- package/skills/backend/microservices-architect/references/data.md +721 -721
- package/skills/backend/microservices-architect/references/decomposition.md +344 -344
- package/skills/backend/microservices-architect/references/observability.md +805 -805
- package/skills/backend/microservices-architect/references/patterns.md +603 -603
- package/skills/database/database-optimizer/SKILL.md +147 -147
- package/skills/database/database-optimizer/references/index-strategies.md +331 -331
- package/skills/database/database-optimizer/references/monitoring-analysis.md +501 -501
- package/skills/database/database-optimizer/references/mysql-tuning.md +452 -452
- package/skills/database/database-optimizer/references/postgresql-tuning.md +413 -413
- package/skills/database/database-optimizer/references/query-optimization.md +251 -251
- package/skills/database/postgres-pro/SKILL.md +152 -152
- package/skills/database/postgres-pro/references/extensions.md +404 -404
- package/skills/database/postgres-pro/references/jsonb.md +321 -321
- package/skills/database/postgres-pro/references/maintenance.md +481 -481
- package/skills/database/postgres-pro/references/performance.md +265 -265
- package/skills/database/postgres-pro/references/replication.md +446 -446
- package/skills/database/sql-pro/SKILL.md +129 -129
- package/skills/database/sql-pro/references/database-design.md +402 -402
- package/skills/database/sql-pro/references/dialect-differences.md +419 -419
- package/skills/database/sql-pro/references/optimization.md +384 -384
- package/skills/database/sql-pro/references/query-patterns.md +285 -285
- package/skills/database/sql-pro/references/window-functions.md +328 -328
- package/skills/dotnet/csharp-developer/SKILL.md +125 -125
- package/skills/dotnet/csharp-developer/references/aspnet-core.md +394 -394
- package/skills/dotnet/csharp-developer/references/blazor.md +553 -553
- package/skills/dotnet/csharp-developer/references/entity-framework.md +409 -409
- package/skills/dotnet/csharp-developer/references/modern-csharp.md +248 -248
- package/skills/dotnet/csharp-developer/references/performance.md +498 -498
- package/skills/dotnet/dotnet-core-expert/SKILL.md +138 -138
- package/skills/dotnet/dotnet-core-expert/references/authentication.md +546 -546
- package/skills/dotnet/dotnet-core-expert/references/clean-architecture.md +455 -455
- package/skills/dotnet/dotnet-core-expert/references/cloud-native.md +548 -548
- package/skills/dotnet/dotnet-core-expert/references/entity-framework.md +440 -440
- package/skills/dotnet/dotnet-core-expert/references/minimal-apis.md +319 -319
- package/skills/frontend/angular-architect/SKILL.md +152 -152
- package/skills/frontend/angular-architect/references/components.md +297 -297
- package/skills/frontend/angular-architect/references/ngrx.md +401 -401
- package/skills/frontend/angular-architect/references/routing.md +361 -361
- package/skills/frontend/angular-architect/references/rxjs.md +319 -319
- package/skills/frontend/angular-architect/references/testing.md +405 -405
- package/skills/frontend/design-commands/design.md +91 -91
- package/skills/frontend/design-commands/handoff.md +97 -97
- package/skills/frontend/design-commands/prototype.md +120 -120
- package/skills/frontend/design-commands/spec.md +160 -160
- package/skills/frontend/design-commands/style.md +78 -78
- package/skills/frontend/flutter-expert/SKILL.md +138 -138
- package/skills/frontend/flutter-expert/references/bloc-state.md +259 -259
- package/skills/frontend/flutter-expert/references/gorouter-navigation.md +119 -119
- package/skills/frontend/flutter-expert/references/performance.md +99 -99
- package/skills/frontend/flutter-expert/references/project-structure.md +118 -118
- package/skills/frontend/flutter-expert/references/riverpod-state.md +130 -130
- package/skills/frontend/flutter-expert/references/widget-patterns.md +123 -123
- package/skills/frontend/nextjs-developer/SKILL.md +143 -143
- package/skills/frontend/nextjs-developer/references/app-router.md +311 -311
- package/skills/frontend/nextjs-developer/references/data-fetching.md +482 -482
- package/skills/frontend/nextjs-developer/references/deployment.md +545 -545
- package/skills/frontend/nextjs-developer/references/server-actions.md +462 -462
- package/skills/frontend/nextjs-developer/references/server-components.md +384 -384
- package/skills/frontend/react-expert/SKILL.md +149 -149
- package/skills/frontend/react-expert/references/hooks-patterns.md +162 -162
- package/skills/frontend/react-expert/references/migration-class-to-modern.md +1119 -1119
- package/skills/frontend/react-expert/references/performance.md +168 -168
- package/skills/frontend/react-expert/references/react-19-features.md +174 -174
- package/skills/frontend/react-expert/references/server-components.md +143 -143
- package/skills/frontend/react-expert/references/state-management.md +171 -171
- package/skills/frontend/react-expert/references/testing-react.md +174 -174
- package/skills/frontend/react-native-expert/SKILL.md +185 -185
- package/skills/frontend/react-native-expert/references/expo-router.md +187 -187
- package/skills/frontend/react-native-expert/references/list-optimization.md +204 -204
- package/skills/frontend/react-native-expert/references/platform-handling.md +188 -188
- package/skills/frontend/react-native-expert/references/project-structure.md +171 -171
- package/skills/frontend/react-native-expert/references/storage-hooks.md +173 -173
- package/skills/frontend/senior-frontend/SKILL.md +477 -477
- package/skills/frontend/senior-frontend/references/frontend_best_practices.md +806 -806
- package/skills/frontend/senior-frontend/references/nextjs_optimization_guide.md +724 -724
- package/skills/frontend/senior-frontend/references/react_patterns.md +746 -746
- package/skills/frontend/senior-frontend/scripts/bundle_analyzer.py +407 -407
- package/skills/frontend/senior-frontend/scripts/component_generator.py +329 -329
- package/skills/frontend/senior-frontend/scripts/frontend_scaffolder.py +1005 -1005
- package/skills/frontend/ui-ux-pro-max/SKILL.md +386 -386
- package/skills/frontend/ui-ux-pro-max/data/charts.csv +26 -26
- package/skills/frontend/ui-ux-pro-max/data/colors.csv +97 -97
- package/skills/frontend/ui-ux-pro-max/data/icons.csv +101 -101
- package/skills/frontend/ui-ux-pro-max/data/landing.csv +31 -31
- package/skills/frontend/ui-ux-pro-max/data/products.csv +96 -96
- package/skills/frontend/ui-ux-pro-max/data/react-performance.csv +45 -45
- package/skills/frontend/ui-ux-pro-max/data/stacks/astro.csv +54 -54
- package/skills/frontend/ui-ux-pro-max/data/stacks/flutter.csv +53 -53
- package/skills/frontend/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -56
- package/skills/frontend/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -53
- package/skills/frontend/ui-ux-pro-max/data/stacks/nextjs.csv +53 -53
- package/skills/frontend/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -51
- package/skills/frontend/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -59
- package/skills/frontend/ui-ux-pro-max/data/stacks/react-native.csv +52 -52
- package/skills/frontend/ui-ux-pro-max/data/stacks/react.csv +54 -54
- package/skills/frontend/ui-ux-pro-max/data/stacks/shadcn.csv +61 -61
- package/skills/frontend/ui-ux-pro-max/data/stacks/svelte.csv +54 -54
- package/skills/frontend/ui-ux-pro-max/data/stacks/swiftui.csv +51 -51
- package/skills/frontend/ui-ux-pro-max/data/stacks/vue.csv +50 -50
- package/skills/frontend/ui-ux-pro-max/data/styles.csv +68 -68
- package/skills/frontend/ui-ux-pro-max/data/typography.csv +57 -57
- package/skills/frontend/ui-ux-pro-max/data/ui-reasoning.csv +101 -101
- package/skills/frontend/ui-ux-pro-max/data/ux-guidelines.csv +99 -99
- package/skills/frontend/ui-ux-pro-max/data/web-interface.csv +31 -31
- package/skills/frontend/ui-ux-pro-max/scripts/core.py +253 -253
- package/skills/frontend/ui-ux-pro-max/scripts/design_system.py +1067 -1067
- package/skills/frontend/ui-ux-pro-max/scripts/search.py +114 -114
- package/skills/frontend/vue-expert/SKILL.md +98 -98
- package/skills/frontend/vue-expert/references/build-tooling.md +480 -480
- package/skills/frontend/vue-expert/references/components.md +448 -448
- package/skills/frontend/vue-expert/references/composition-api.md +299 -299
- package/skills/frontend/vue-expert/references/mobile-hybrid.md +636 -636
- package/skills/frontend/vue-expert/references/nuxt.md +669 -669
- package/skills/frontend/vue-expert/references/state-management.md +449 -449
- package/skills/frontend/vue-expert/references/typescript.md +584 -584
- package/skills/frontend/vue-expert-js/SKILL.md +167 -167
- package/skills/frontend/vue-expert-js/references/component-architecture.md +219 -219
- package/skills/frontend/vue-expert-js/references/composables-patterns.md +183 -183
- package/skills/frontend/vue-expert-js/references/jsdoc-typing.md +535 -535
- package/skills/frontend/vue-expert-js/references/state-management.md +249 -249
- package/skills/frontend/vue-expert-js/references/testing-patterns.md +237 -237
- package/skills/go-rust-cpp/cpp-pro/SKILL.md +115 -115
- package/skills/go-rust-cpp/cpp-pro/references/build-tooling.md +440 -440
- package/skills/go-rust-cpp/cpp-pro/references/concurrency.md +437 -437
- package/skills/go-rust-cpp/cpp-pro/references/memory-performance.md +397 -397
- package/skills/go-rust-cpp/cpp-pro/references/modern-cpp.md +304 -304
- package/skills/go-rust-cpp/cpp-pro/references/templates.md +357 -357
- package/skills/go-rust-cpp/golang-pro/SKILL.md +122 -122
- package/skills/go-rust-cpp/golang-pro/references/concurrency.md +329 -329
- package/skills/go-rust-cpp/golang-pro/references/generics.md +442 -442
- package/skills/go-rust-cpp/golang-pro/references/interfaces.md +432 -432
- package/skills/go-rust-cpp/golang-pro/references/project-structure.md +477 -477
- package/skills/go-rust-cpp/golang-pro/references/testing.md +451 -451
- package/skills/go-rust-cpp/rust-engineer/SKILL.md +167 -167
- package/skills/go-rust-cpp/rust-engineer/references/async.md +458 -458
- package/skills/go-rust-cpp/rust-engineer/references/error-handling.md +334 -334
- package/skills/go-rust-cpp/rust-engineer/references/ownership.md +278 -278
- package/skills/go-rust-cpp/rust-engineer/references/testing.md +470 -470
- package/skills/go-rust-cpp/rust-engineer/references/traits.md +413 -413
- package/skills/infra/cli-developer/SKILL.md +113 -113
- package/skills/infra/cli-developer/references/design-patterns.md +221 -221
- package/skills/infra/cli-developer/references/go-cli.md +540 -540
- package/skills/infra/cli-developer/references/node-cli.md +383 -383
- package/skills/infra/cli-developer/references/python-cli.md +422 -422
- package/skills/infra/cli-developer/references/ux-patterns.md +448 -448
- package/skills/infra/cloud-architect/SKILL.md +216 -216
- package/skills/infra/cloud-architect/references/aws.md +394 -394
- package/skills/infra/cloud-architect/references/azure.md +562 -562
- package/skills/infra/cloud-architect/references/cost.md +582 -582
- package/skills/infra/cloud-architect/references/gcp.md +633 -633
- package/skills/infra/cloud-architect/references/multi-cloud.md +483 -483
- package/skills/infra/devops-engineer/SKILL.md +144 -144
- package/skills/infra/devops-engineer/references/deployment-strategies.md +241 -241
- package/skills/infra/devops-engineer/references/docker-patterns.md +113 -113
- package/skills/infra/devops-engineer/references/github-actions.md +139 -139
- package/skills/infra/devops-engineer/references/incident-response.md +331 -331
- package/skills/infra/devops-engineer/references/kubernetes.md +154 -154
- package/skills/infra/devops-engineer/references/platform-engineering.md +417 -417
- package/skills/infra/devops-engineer/references/release-automation.md +527 -527
- package/skills/infra/devops-engineer/references/terraform-iac.md +141 -141
- package/skills/infra/kubernetes-specialist/SKILL.md +241 -241
- package/skills/infra/kubernetes-specialist/references/configuration.md +452 -452
- package/skills/infra/kubernetes-specialist/references/cost-optimization.md +458 -458
- package/skills/infra/kubernetes-specialist/references/custom-operators.md +563 -563
- package/skills/infra/kubernetes-specialist/references/gitops.md +530 -530
- package/skills/infra/kubernetes-specialist/references/helm-charts.md +912 -912
- package/skills/infra/kubernetes-specialist/references/multi-cluster.md +507 -507
- package/skills/infra/kubernetes-specialist/references/networking.md +447 -447
- package/skills/infra/kubernetes-specialist/references/service-mesh.md +459 -459
- package/skills/infra/kubernetes-specialist/references/storage.md +535 -535
- package/skills/infra/kubernetes-specialist/references/troubleshooting.md +414 -414
- package/skills/infra/kubernetes-specialist/references/workloads.md +377 -377
- package/skills/infra/mcp-developer/SKILL.md +143 -143
- package/skills/infra/mcp-developer/references/protocol.md +244 -244
- package/skills/infra/mcp-developer/references/python-sdk.md +367 -367
- package/skills/infra/mcp-developer/references/resources.md +554 -554
- package/skills/infra/mcp-developer/references/tools.md +480 -480
- package/skills/infra/mcp-developer/references/typescript-sdk.md +350 -350
- package/skills/infra/monitoring-expert/SKILL.md +176 -176
- package/skills/infra/monitoring-expert/references/alerting-rules.md +141 -141
- package/skills/infra/monitoring-expert/references/application-profiling.md +331 -331
- package/skills/infra/monitoring-expert/references/capacity-planning.md +344 -344
- package/skills/infra/monitoring-expert/references/dashboards.md +126 -126
- package/skills/infra/monitoring-expert/references/opentelemetry.md +123 -123
- package/skills/infra/monitoring-expert/references/performance-testing.md +269 -269
- package/skills/infra/monitoring-expert/references/prometheus-metrics.md +136 -136
- package/skills/infra/monitoring-expert/references/structured-logging.md +142 -142
- package/skills/infra/sre-engineer/SKILL.md +181 -181
- package/skills/infra/sre-engineer/references/automation-toil.md +492 -492
- package/skills/infra/sre-engineer/references/error-budget-policy.md +334 -334
- package/skills/infra/sre-engineer/references/incident-chaos.md +576 -576
- package/skills/infra/sre-engineer/references/monitoring-alerting.md +424 -424
- package/skills/infra/sre-engineer/references/slo-sli-management.md +238 -238
- package/skills/infra/terraform-engineer/SKILL.md +143 -143
- package/skills/infra/terraform-engineer/references/best-practices.md +583 -583
- package/skills/infra/terraform-engineer/references/module-patterns.md +297 -297
- package/skills/infra/terraform-engineer/references/providers.md +452 -452
- package/skills/infra/terraform-engineer/references/state-management.md +371 -371
- package/skills/infra/terraform-engineer/references/testing.md +486 -486
- package/skills/infra/websocket-engineer/SKILL.md +168 -168
- package/skills/infra/websocket-engineer/references/alternatives.md +391 -391
- package/skills/infra/websocket-engineer/references/patterns.md +400 -400
- package/skills/infra/websocket-engineer/references/protocol.md +195 -195
- package/skills/infra/websocket-engineer/references/scaling.md +333 -333
- package/skills/infra/websocket-engineer/references/security.md +474 -474
- package/skills/java/java-architect/SKILL.md +132 -132
- package/skills/java/java-architect/references/jpa-optimization.md +393 -393
- package/skills/java/java-architect/references/reactive-webflux.md +356 -356
- package/skills/java/java-architect/references/spring-boot-setup.md +269 -269
- package/skills/java/java-architect/references/spring-security.md +445 -445
- package/skills/java/java-architect/references/testing-patterns.md +500 -500
- package/skills/java/kotlin-specialist/SKILL.md +147 -147
- package/skills/java/kotlin-specialist/references/android-compose.md +419 -419
- package/skills/java/kotlin-specialist/references/coroutines-flow.md +276 -276
- package/skills/java/kotlin-specialist/references/dsl-idioms.md +421 -421
- package/skills/java/kotlin-specialist/references/ktor-server.md +426 -426
- package/skills/java/kotlin-specialist/references/multiplatform-kmp.md +380 -380
- package/skills/java/spring-boot-engineer/SKILL.md +195 -195
- package/skills/java/spring-boot-engineer/references/cloud.md +498 -498
- package/skills/java/spring-boot-engineer/references/data.md +381 -381
- package/skills/java/spring-boot-engineer/references/security.md +459 -459
- package/skills/java/spring-boot-engineer/references/testing.md +545 -545
- package/skills/java/spring-boot-engineer/references/web.md +295 -295
- package/skills/javascript/javascript-pro/SKILL.md +132 -132
- package/skills/javascript/javascript-pro/references/async-patterns.md +334 -334
- package/skills/javascript/javascript-pro/references/browser-apis.md +398 -398
- package/skills/javascript/javascript-pro/references/modern-syntax.md +272 -272
- package/skills/javascript/javascript-pro/references/modules.md +357 -357
- package/skills/javascript/javascript-pro/references/node-essentials.md +471 -471
- package/skills/javascript/nestjs-expert/SKILL.md +206 -206
- package/skills/javascript/nestjs-expert/references/authentication.md +166 -166
- package/skills/javascript/nestjs-expert/references/controllers-routing.md +111 -111
- package/skills/javascript/nestjs-expert/references/dtos-validation.md +153 -153
- package/skills/javascript/nestjs-expert/references/migration-from-express.md +1237 -1237
- package/skills/javascript/nestjs-expert/references/services-di.md +140 -140
- package/skills/javascript/nestjs-expert/references/testing-patterns.md +186 -186
- package/skills/javascript/typescript-pro/SKILL.md +145 -145
- package/skills/javascript/typescript-pro/references/advanced-types.md +259 -259
- package/skills/javascript/typescript-pro/references/configuration.md +445 -445
- package/skills/javascript/typescript-pro/references/patterns.md +484 -484
- package/skills/javascript/typescript-pro/references/type-guards.md +352 -352
- package/skills/javascript/typescript-pro/references/utility-types.md +329 -329
- package/skills/php/laravel-specialist/SKILL.md +262 -262
- package/skills/php/laravel-specialist/references/eloquent.md +351 -351
- package/skills/php/laravel-specialist/references/livewire.md +512 -512
- package/skills/php/laravel-specialist/references/queues.md +423 -423
- package/skills/php/laravel-specialist/references/routing.md +362 -362
- package/skills/php/laravel-specialist/references/testing.md +522 -522
- package/skills/php/php-pro/SKILL.md +206 -206
- package/skills/php/php-pro/references/async-patterns.md +412 -412
- package/skills/php/php-pro/references/laravel-patterns.md +377 -377
- package/skills/php/php-pro/references/modern-php-features.md +323 -323
- package/skills/php/php-pro/references/symfony-patterns.md +466 -466
- package/skills/php/php-pro/references/testing-quality.md +466 -466
- package/skills/product/competitive-analysis/SKILL.md +257 -257
- package/skills/product/meeting-notes/SKILL.md +266 -266
- package/skills/product/prd-template/SKILL.md +150 -150
- package/skills/product/stakeholder-update/SKILL.md +225 -225
- package/skills/product/user-research-synthesis/SKILL.md +235 -235
- package/skills/python/django-expert/SKILL.md +162 -162
- package/skills/python/django-expert/references/authentication.md +145 -145
- package/skills/python/django-expert/references/drf-serializers.md +148 -148
- package/skills/python/django-expert/references/models-orm.md +151 -151
- package/skills/python/django-expert/references/testing-django.md +204 -204
- package/skills/python/django-expert/references/viewsets-views.md +153 -153
- package/skills/python/fastapi-expert/SKILL.md +185 -185
- package/skills/python/fastapi-expert/references/async-sqlalchemy.md +146 -146
- package/skills/python/fastapi-expert/references/authentication.md +159 -159
- package/skills/python/fastapi-expert/references/endpoints-routing.md +142 -142
- package/skills/python/fastapi-expert/references/migration-from-django.md +996 -996
- package/skills/python/fastapi-expert/references/pydantic-v2.md +135 -135
- package/skills/python/fastapi-expert/references/testing-async.md +159 -159
- package/skills/python/pandas-pro/SKILL.md +178 -178
- package/skills/python/pandas-pro/references/aggregation-groupby.md +545 -545
- package/skills/python/pandas-pro/references/data-cleaning.md +500 -500
- package/skills/python/pandas-pro/references/dataframe-operations.md +420 -420
- package/skills/python/pandas-pro/references/merging-joining.md +596 -596
- package/skills/python/pandas-pro/references/performance-optimization.md +597 -597
- package/skills/python/python-pro/SKILL.md +177 -177
- package/skills/python/python-pro/references/async-patterns.md +356 -356
- package/skills/python/python-pro/references/packaging.md +460 -460
- package/skills/python/python-pro/references/standard-library.md +378 -378
- package/skills/python/python-pro/references/testing.md +404 -404
- package/skills/python/python-pro/references/type-system.md +290 -290
- package/skills/quality/chaos-engineer/SKILL.md +182 -182
- package/skills/quality/chaos-engineer/references/chaos-tools.md +511 -511
- package/skills/quality/chaos-engineer/references/experiment-design.md +229 -229
- package/skills/quality/chaos-engineer/references/game-days.md +434 -434
- package/skills/quality/chaos-engineer/references/infrastructure-chaos.md +348 -348
- package/skills/quality/chaos-engineer/references/kubernetes-chaos.md +432 -432
- package/skills/quality/code-reviewer/SKILL.md +119 -119
- package/skills/quality/code-reviewer/references/common-issues.md +142 -142
- package/skills/quality/code-reviewer/references/feedback-examples.md +144 -144
- package/skills/quality/code-reviewer/references/receiving-feedback.md +238 -238
- package/skills/quality/code-reviewer/references/report-template.md +109 -109
- package/skills/quality/code-reviewer/references/review-checklist.md +88 -88
- package/skills/quality/code-reviewer/references/spec-compliance-review.md +258 -258
- package/skills/quality/playwright-expert/SKILL.md +169 -169
- package/skills/quality/playwright-expert/references/api-mocking.md +140 -140
- package/skills/quality/playwright-expert/references/configuration.md +155 -155
- package/skills/quality/playwright-expert/references/debugging-flaky.md +150 -150
- package/skills/quality/playwright-expert/references/page-object-model.md +152 -152
- package/skills/quality/playwright-expert/references/selectors-locators.md +119 -119
- package/skills/quality/secure-code-guardian/SKILL.md +191 -191
- package/skills/quality/secure-code-guardian/references/authentication.md +136 -136
- package/skills/quality/secure-code-guardian/references/input-validation.md +146 -146
- package/skills/quality/secure-code-guardian/references/owasp-prevention.md +135 -135
- package/skills/quality/secure-code-guardian/references/security-headers.md +133 -133
- package/skills/quality/secure-code-guardian/references/xss-csrf.md +157 -157
- package/skills/quality/security-reviewer/SKILL.md +103 -103
- package/skills/quality/security-reviewer/references/infrastructure-security.md +268 -268
- package/skills/quality/security-reviewer/references/penetration-testing.md +268 -268
- package/skills/quality/security-reviewer/references/report-template.md +170 -170
- package/skills/quality/security-reviewer/references/sast-tools.md +117 -117
- package/skills/quality/security-reviewer/references/secret-scanning.md +125 -125
- package/skills/quality/security-reviewer/references/vulnerability-patterns.md +152 -152
- package/skills/quality/senior-qa/README.md +196 -196
- package/skills/quality/senior-qa/SKILL.md +399 -399
- package/skills/quality/senior-qa/references/qa_best_practices.md +964 -964
- package/skills/quality/senior-qa/references/test_automation_patterns.md +1009 -1009
- package/skills/quality/senior-qa/references/testing_strategies.md +649 -649
- package/skills/quality/senior-qa/scripts/coverage_analyzer.py +836 -836
- package/skills/quality/senior-qa/scripts/e2e_test_scaffolder.py +820 -820
- package/skills/quality/senior-qa/scripts/test_suite_generator.py +605 -605
- package/skills/quality/tdd-guide/HOW_TO_USE.md +313 -313
- package/skills/quality/tdd-guide/README.md +680 -680
- package/skills/quality/tdd-guide/SKILL.md +122 -122
- package/skills/quality/tdd-guide/assets/expected_output.json +77 -77
- package/skills/quality/tdd-guide/assets/sample_input_python.json +39 -39
- package/skills/quality/tdd-guide/assets/sample_input_typescript.json +36 -36
- package/skills/quality/tdd-guide/references/ci-integration.md +195 -195
- package/skills/quality/tdd-guide/references/framework-guide.md +206 -206
- package/skills/quality/tdd-guide/references/tdd-best-practices.md +128 -128
- package/skills/quality/tdd-guide/scripts/coverage_analyzer.py +434 -434
- package/skills/quality/tdd-guide/scripts/fixture_generator.py +440 -440
- package/skills/quality/tdd-guide/scripts/format_detector.py +384 -384
- package/skills/quality/tdd-guide/scripts/framework_adapter.py +428 -428
- package/skills/quality/tdd-guide/scripts/metrics_calculator.py +456 -456
- package/skills/quality/tdd-guide/scripts/output_formatter.py +354 -354
- package/skills/quality/tdd-guide/scripts/tdd_workflow.py +474 -474
- package/skills/quality/tdd-guide/scripts/test_generator.py +438 -438
- package/skills/quality/test-master/SKILL.md +94 -94
- package/skills/quality/test-master/references/automation-frameworks.md +294 -294
- package/skills/quality/test-master/references/e2e-testing.md +128 -128
- package/skills/quality/test-master/references/integration-testing.md +120 -120
- package/skills/quality/test-master/references/performance-testing.md +118 -118
- package/skills/quality/test-master/references/qa-methodology.md +247 -247
- package/skills/quality/test-master/references/security-testing.md +127 -127
- package/skills/quality/test-master/references/tdd-iron-laws.md +174 -174
- package/skills/quality/test-master/references/test-reports.md +104 -104
- package/skills/quality/test-master/references/testing-anti-patterns.md +231 -231
- package/skills/quality/test-master/references/unit-testing.md +113 -113
- package/skills/ruby/rails-expert/SKILL.md +154 -154
- package/skills/ruby/rails-expert/references/active-record.md +244 -244
- package/skills/ruby/rails-expert/references/api-development.md +401 -401
- package/skills/ruby/rails-expert/references/background-jobs.md +272 -272
- package/skills/ruby/rails-expert/references/hotwire-turbo.md +228 -228
- package/skills/ruby/rails-expert/references/rspec-testing.md +367 -367
- package/skills/swift/swift-expert/SKILL.md +163 -163
- package/skills/swift/swift-expert/references/async-concurrency.md +360 -360
- package/skills/swift/swift-expert/references/memory-performance.md +377 -377
- package/skills/swift/swift-expert/references/protocol-oriented.md +354 -354
- package/skills/swift/swift-expert/references/swiftui-patterns.md +291 -291
- package/skills/swift/swift-expert/references/testing-patterns.md +399 -399
- package/skills/workflow/brainstorming/SKILL.md +164 -164
- package/skills/workflow/brainstorming/scripts/frame-template.html +214 -214
- package/skills/workflow/brainstorming/scripts/helper.js +88 -88
- package/skills/workflow/brainstorming/scripts/server.cjs +354 -354
- package/skills/workflow/brainstorming/scripts/start-server.sh +148 -148
- package/skills/workflow/brainstorming/scripts/stop-server.sh +56 -56
- package/skills/workflow/brainstorming/spec-document-reviewer-prompt.md +49 -49
- package/skills/workflow/brainstorming/visual-companion.md +287 -287
- package/skills/workflow/documentation/SKILL.md +45 -45
- package/skills/workflow/entropy-management/SKILL.md +115 -115
- package/skills/workflow/executing-plans/SKILL.md +70 -70
- package/skills/workflow/finishing-a-development-branch/SKILL.md +200 -200
- package/skills/workflow/receiving-code-review/SKILL.md +213 -213
- package/skills/workflow/requesting-code-review/SKILL.md +105 -105
- package/skills/workflow/requesting-code-review/code-reviewer.md +146 -146
- package/skills/workflow/requirement-engineering/SKILL.md +111 -111
- package/skills/workflow/systematic-debugging/CREATION-LOG.md +119 -119
- package/skills/workflow/systematic-debugging/SKILL.md +296 -296
- package/skills/workflow/systematic-debugging/condition-based-waiting-example.ts +158 -158
- package/skills/workflow/systematic-debugging/condition-based-waiting.md +115 -115
- package/skills/workflow/systematic-debugging/defense-in-depth.md +122 -122
- package/skills/workflow/systematic-debugging/find-polluter.sh +63 -63
- package/skills/workflow/systematic-debugging/root-cause-tracing.md +169 -169
- package/skills/workflow/systematic-debugging/test-academic.md +14 -14
- package/skills/workflow/systematic-debugging/test-pressure-1.md +58 -58
- package/skills/workflow/systematic-debugging/test-pressure-2.md +68 -68
- package/skills/workflow/systematic-debugging/test-pressure-3.md +69 -69
- package/skills/workflow/using-git-worktrees/SKILL.md +218 -218
- package/skills/workflow/verification-before-completion/SKILL.md +139 -139
- package/skills/workflow/writing-plans/SKILL.md +151 -151
- package/skills/workflow/writing-plans/plan-document-reviewer-prompt.md +49 -49
- package/skills/workflow/writing-skills/SKILL.md +655 -655
- package/skills/workflow/writing-skills/anthropic-best-practices.md +1150 -1150
- package/skills/workflow/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -189
- package/skills/workflow/writing-skills/persuasion-principles.md +187 -187
- package/skills/workflow/writing-skills/render-graphs.js +168 -168
- package/skills/workflow/writing-skills/testing-skills-with-subagents.md +384 -384
|
@@ -1,445 +1,445 @@
|
|
|
1
|
-
# Spring Security
|
|
2
|
-
|
|
3
|
-
## Security Configuration
|
|
4
|
-
|
|
5
|
-
```java
|
|
6
|
-
package com.example.infrastructure.security;
|
|
7
|
-
|
|
8
|
-
import lombok.RequiredArgsConstructor;
|
|
9
|
-
import org.springframework.context.annotation.Bean;
|
|
10
|
-
import org.springframework.context.annotation.Configuration;
|
|
11
|
-
import org.springframework.security.authentication.AuthenticationManager;
|
|
12
|
-
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
|
13
|
-
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
|
14
|
-
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
|
15
|
-
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|
16
|
-
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
|
17
|
-
import org.springframework.security.config.http.SessionCreationPolicy;
|
|
18
|
-
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
|
19
|
-
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
20
|
-
import org.springframework.security.web.SecurityFilterChain;
|
|
21
|
-
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
|
22
|
-
|
|
23
|
-
@Configuration
|
|
24
|
-
@EnableWebSecurity
|
|
25
|
-
@EnableMethodSecurity(securedEnabled = true, jsr250Enabled = true)
|
|
26
|
-
@RequiredArgsConstructor
|
|
27
|
-
public class SecurityConfig {
|
|
28
|
-
|
|
29
|
-
private final JwtAuthenticationFilter jwtAuthFilter;
|
|
30
|
-
private final CustomUserDetailsService userDetailsService;
|
|
31
|
-
|
|
32
|
-
@Bean
|
|
33
|
-
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
|
34
|
-
return http
|
|
35
|
-
.csrf(csrf -> csrf.disable())
|
|
36
|
-
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
|
|
37
|
-
.authorizeHttpRequests(auth -> auth
|
|
38
|
-
.requestMatchers("/api/auth/**", "/api/public/**").permitAll()
|
|
39
|
-
.requestMatchers("/actuator/health", "/actuator/info").permitAll()
|
|
40
|
-
.requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll()
|
|
41
|
-
.requestMatchers("/api/admin/**").hasRole("ADMIN")
|
|
42
|
-
.anyRequest().authenticated()
|
|
43
|
-
)
|
|
44
|
-
.sessionManagement(session -> session
|
|
45
|
-
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
|
46
|
-
)
|
|
47
|
-
.authenticationProvider(authenticationProvider())
|
|
48
|
-
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
|
|
49
|
-
.build();
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
@Bean
|
|
53
|
-
public DaoAuthenticationProvider authenticationProvider() {
|
|
54
|
-
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
|
55
|
-
provider.setUserDetailsService(userDetailsService);
|
|
56
|
-
provider.setPasswordEncoder(passwordEncoder());
|
|
57
|
-
return provider;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
@Bean
|
|
61
|
-
public AuthenticationManager authenticationManager(
|
|
62
|
-
AuthenticationConfiguration config
|
|
63
|
-
) throws Exception {
|
|
64
|
-
return config.getAuthenticationManager();
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
@Bean
|
|
68
|
-
public PasswordEncoder passwordEncoder() {
|
|
69
|
-
return new BCryptPasswordEncoder(12);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
@Bean
|
|
73
|
-
public CorsConfigurationSource corsConfigurationSource() {
|
|
74
|
-
CorsConfiguration configuration = new CorsConfiguration();
|
|
75
|
-
configuration.setAllowedOrigins(List.of("http://localhost:3000"));
|
|
76
|
-
configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
|
|
77
|
-
configuration.setAllowedHeaders(List.of("*"));
|
|
78
|
-
configuration.setAllowCredentials(true);
|
|
79
|
-
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
|
80
|
-
source.registerCorsConfiguration("/**", configuration);
|
|
81
|
-
return source;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
## JWT Authentication Filter
|
|
87
|
-
|
|
88
|
-
```java
|
|
89
|
-
package com.example.infrastructure.security;
|
|
90
|
-
|
|
91
|
-
import jakarta.servlet.FilterChain;
|
|
92
|
-
import jakarta.servlet.ServletException;
|
|
93
|
-
import jakarta.servlet.http.HttpServletRequest;
|
|
94
|
-
import jakarta.servlet.http.HttpServletResponse;
|
|
95
|
-
import lombok.RequiredArgsConstructor;
|
|
96
|
-
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
97
|
-
import org.springframework.security.core.context.SecurityContextHolder;
|
|
98
|
-
import org.springframework.security.core.userdetails.UserDetails;
|
|
99
|
-
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
|
100
|
-
import org.springframework.stereotype.Component;
|
|
101
|
-
import org.springframework.web.filter.OncePerRequestFilter;
|
|
102
|
-
|
|
103
|
-
import java.io.IOException;
|
|
104
|
-
|
|
105
|
-
@Component
|
|
106
|
-
@RequiredArgsConstructor
|
|
107
|
-
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
|
108
|
-
|
|
109
|
-
private final JwtService jwtService;
|
|
110
|
-
private final CustomUserDetailsService userDetailsService;
|
|
111
|
-
|
|
112
|
-
@Override
|
|
113
|
-
protected void doFilterInternal(
|
|
114
|
-
HttpServletRequest request,
|
|
115
|
-
HttpServletResponse response,
|
|
116
|
-
FilterChain filterChain
|
|
117
|
-
) throws ServletException, IOException {
|
|
118
|
-
|
|
119
|
-
String authHeader = request.getHeader("Authorization");
|
|
120
|
-
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
|
|
121
|
-
filterChain.doFilter(request, response);
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
String jwt = authHeader.substring(7);
|
|
126
|
-
String userEmail = jwtService.extractUsername(jwt);
|
|
127
|
-
|
|
128
|
-
if (userEmail != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
|
129
|
-
UserDetails userDetails = userDetailsService.loadUserByUsername(userEmail);
|
|
130
|
-
|
|
131
|
-
if (jwtService.isTokenValid(jwt, userDetails)) {
|
|
132
|
-
UsernamePasswordAuthenticationToken authToken =
|
|
133
|
-
new UsernamePasswordAuthenticationToken(
|
|
134
|
-
userDetails,
|
|
135
|
-
null,
|
|
136
|
-
userDetails.getAuthorities()
|
|
137
|
-
);
|
|
138
|
-
authToken.setDetails(
|
|
139
|
-
new WebAuthenticationDetailsSource().buildDetails(request)
|
|
140
|
-
);
|
|
141
|
-
SecurityContextHolder.getContext().setAuthentication(authToken);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
filterChain.doFilter(request, response);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
## JWT Service
|
|
151
|
-
|
|
152
|
-
```java
|
|
153
|
-
package com.example.infrastructure.security;
|
|
154
|
-
|
|
155
|
-
import io.jsonwebtoken.Claims;
|
|
156
|
-
import io.jsonwebtoken.Jwts;
|
|
157
|
-
import io.jsonwebtoken.SignatureAlgorithm;
|
|
158
|
-
import io.jsonwebtoken.io.Decoders;
|
|
159
|
-
import io.jsonwebtoken.security.Keys;
|
|
160
|
-
import org.springframework.beans.factory.annotation.Value;
|
|
161
|
-
import org.springframework.security.core.userdetails.UserDetails;
|
|
162
|
-
import org.springframework.stereotype.Service;
|
|
163
|
-
|
|
164
|
-
import java.security.Key;
|
|
165
|
-
import java.util.Date;
|
|
166
|
-
import java.util.HashMap;
|
|
167
|
-
import java.util.Map;
|
|
168
|
-
import java.util.function.Function;
|
|
169
|
-
|
|
170
|
-
@Service
|
|
171
|
-
public class JwtService {
|
|
172
|
-
|
|
173
|
-
@Value("${jwt.secret}")
|
|
174
|
-
private String secretKey;
|
|
175
|
-
|
|
176
|
-
@Value("${jwt.expiration}")
|
|
177
|
-
private long jwtExpiration;
|
|
178
|
-
|
|
179
|
-
@Value("${jwt.refresh-expiration}")
|
|
180
|
-
private long refreshExpiration;
|
|
181
|
-
|
|
182
|
-
public String extractUsername(String token) {
|
|
183
|
-
return extractClaim(token, Claims::getSubject);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
|
|
187
|
-
final Claims claims = extractAllClaims(token);
|
|
188
|
-
return claimsResolver.apply(claims);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
public String generateToken(UserDetails userDetails) {
|
|
192
|
-
return generateToken(new HashMap<>(), userDetails);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
public String generateToken(
|
|
196
|
-
Map<String, Object> extraClaims,
|
|
197
|
-
UserDetails userDetails
|
|
198
|
-
) {
|
|
199
|
-
return buildToken(extraClaims, userDetails, jwtExpiration);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
public String generateRefreshToken(UserDetails userDetails) {
|
|
203
|
-
return buildToken(new HashMap<>(), userDetails, refreshExpiration);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
private String buildToken(
|
|
207
|
-
Map<String, Object> extraClaims,
|
|
208
|
-
UserDetails userDetails,
|
|
209
|
-
long expiration
|
|
210
|
-
) {
|
|
211
|
-
return Jwts.builder()
|
|
212
|
-
.setClaims(extraClaims)
|
|
213
|
-
.setSubject(userDetails.getUsername())
|
|
214
|
-
.setIssuedAt(new Date(System.currentTimeMillis()))
|
|
215
|
-
.setExpiration(new Date(System.currentTimeMillis() + expiration))
|
|
216
|
-
.signWith(getSignInKey(), SignatureAlgorithm.HS256)
|
|
217
|
-
.compact();
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
public boolean isTokenValid(String token, UserDetails userDetails) {
|
|
221
|
-
final String username = extractUsername(token);
|
|
222
|
-
return (username.equals(userDetails.getUsername())) && !isTokenExpired(token);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
private boolean isTokenExpired(String token) {
|
|
226
|
-
return extractExpiration(token).before(new Date());
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
private Date extractExpiration(String token) {
|
|
230
|
-
return extractClaim(token, Claims::getExpiration);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
private Claims extractAllClaims(String token) {
|
|
234
|
-
return Jwts.parserBuilder()
|
|
235
|
-
.setSigningKey(getSignInKey())
|
|
236
|
-
.build()
|
|
237
|
-
.parseClaimsJws(token)
|
|
238
|
-
.getBody();
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
private Key getSignInKey() {
|
|
242
|
-
byte[] keyBytes = Decoders.BASE64.decode(secretKey);
|
|
243
|
-
return Keys.hmacShaKeyFor(keyBytes);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
## UserDetailsService Implementation
|
|
249
|
-
|
|
250
|
-
```java
|
|
251
|
-
package com.example.infrastructure.security;
|
|
252
|
-
|
|
253
|
-
import com.example.domain.repository.UserRepository;
|
|
254
|
-
import lombok.RequiredArgsConstructor;
|
|
255
|
-
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
|
256
|
-
import org.springframework.security.core.userdetails.UserDetails;
|
|
257
|
-
import org.springframework.security.core.userdetails.UserDetailsService;
|
|
258
|
-
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
|
259
|
-
import org.springframework.stereotype.Service;
|
|
260
|
-
|
|
261
|
-
import java.util.stream.Collectors;
|
|
262
|
-
|
|
263
|
-
@Service
|
|
264
|
-
@RequiredArgsConstructor
|
|
265
|
-
public class CustomUserDetailsService implements UserDetailsService {
|
|
266
|
-
|
|
267
|
-
private final UserRepository userRepository;
|
|
268
|
-
|
|
269
|
-
@Override
|
|
270
|
-
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
|
|
271
|
-
return userRepository.findByEmail(email)
|
|
272
|
-
.map(user -> org.springframework.security.core.userdetails.User.builder()
|
|
273
|
-
.username(user.getEmail())
|
|
274
|
-
.password(user.getPassword())
|
|
275
|
-
.authorities(user.getRoles().stream()
|
|
276
|
-
.map(role -> new SimpleGrantedAuthority(role.getName()))
|
|
277
|
-
.collect(Collectors.toList()))
|
|
278
|
-
.accountExpired(false)
|
|
279
|
-
.accountLocked(!user.getActive())
|
|
280
|
-
.credentialsExpired(false)
|
|
281
|
-
.disabled(!user.getActive())
|
|
282
|
-
.build())
|
|
283
|
-
.orElseThrow(() -> new UsernameNotFoundException("User not found: " + email));
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
## Authentication Controller
|
|
289
|
-
|
|
290
|
-
```java
|
|
291
|
-
package com.example.presentation.rest;
|
|
292
|
-
|
|
293
|
-
import com.example.application.dto.AuthRequest;
|
|
294
|
-
import com.example.application.dto.AuthResponse;
|
|
295
|
-
import com.example.application.dto.RegisterRequest;
|
|
296
|
-
import com.example.application.service.AuthenticationService;
|
|
297
|
-
import jakarta.validation.Valid;
|
|
298
|
-
import lombok.RequiredArgsConstructor;
|
|
299
|
-
import org.springframework.http.ResponseEntity;
|
|
300
|
-
import org.springframework.web.bind.annotation.*;
|
|
301
|
-
|
|
302
|
-
@RestController
|
|
303
|
-
@RequestMapping("/api/auth")
|
|
304
|
-
@RequiredArgsConstructor
|
|
305
|
-
public class AuthenticationController {
|
|
306
|
-
|
|
307
|
-
private final AuthenticationService authService;
|
|
308
|
-
|
|
309
|
-
@PostMapping("/register")
|
|
310
|
-
public ResponseEntity<AuthResponse> register(
|
|
311
|
-
@Valid @RequestBody RegisterRequest request
|
|
312
|
-
) {
|
|
313
|
-
return ResponseEntity.ok(authService.register(request));
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
@PostMapping("/login")
|
|
317
|
-
public ResponseEntity<AuthResponse> authenticate(
|
|
318
|
-
@Valid @RequestBody AuthRequest request
|
|
319
|
-
) {
|
|
320
|
-
return ResponseEntity.ok(authService.authenticate(request));
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
@PostMapping("/refresh")
|
|
324
|
-
public ResponseEntity<AuthResponse> refreshToken(
|
|
325
|
-
@RequestHeader("Authorization") String refreshToken
|
|
326
|
-
) {
|
|
327
|
-
return ResponseEntity.ok(authService.refreshToken(refreshToken));
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
```
|
|
331
|
-
|
|
332
|
-
## Method-Level Security
|
|
333
|
-
|
|
334
|
-
```java
|
|
335
|
-
package com.example.application.service;
|
|
336
|
-
|
|
337
|
-
import lombok.RequiredArgsConstructor;
|
|
338
|
-
import org.springframework.security.access.prepost.PreAuthorize;
|
|
339
|
-
import org.springframework.security.access.prepost.PostAuthorize;
|
|
340
|
-
import org.springframework.stereotype.Service;
|
|
341
|
-
|
|
342
|
-
@Service
|
|
343
|
-
@RequiredArgsConstructor
|
|
344
|
-
public class UserService {
|
|
345
|
-
|
|
346
|
-
private final UserRepository userRepository;
|
|
347
|
-
|
|
348
|
-
@PreAuthorize("hasRole('ADMIN')")
|
|
349
|
-
public List<User> getAllUsers() {
|
|
350
|
-
return userRepository.findAll();
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
@PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
|
|
354
|
-
public User getUserById(Long id) {
|
|
355
|
-
return userRepository.findById(id)
|
|
356
|
-
.orElseThrow(() -> new EntityNotFoundException("User not found"));
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
@PreAuthorize("#user.id == authentication.principal.id or hasRole('ADMIN')")
|
|
360
|
-
public User updateUser(User user) {
|
|
361
|
-
return userRepository.save(user);
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
@PostAuthorize("returnObject.email == authentication.principal.username or hasRole('ADMIN')")
|
|
365
|
-
public User findUserByEmail(String email) {
|
|
366
|
-
return userRepository.findByEmail(email)
|
|
367
|
-
.orElseThrow(() -> new EntityNotFoundException("User not found"));
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
@PreAuthorize("@userSecurityService.hasAccess(#userId)")
|
|
371
|
-
public void deleteUser(Long userId) {
|
|
372
|
-
userRepository.deleteById(userId);
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
## Security Utilities
|
|
378
|
-
|
|
379
|
-
```java
|
|
380
|
-
package com.example.infrastructure.security;
|
|
381
|
-
|
|
382
|
-
import org.springframework.security.core.Authentication;
|
|
383
|
-
import org.springframework.security.core.context.SecurityContextHolder;
|
|
384
|
-
import org.springframework.security.core.userdetails.UserDetails;
|
|
385
|
-
import org.springframework.stereotype.Component;
|
|
386
|
-
|
|
387
|
-
@Component("userSecurityService")
|
|
388
|
-
public class UserSecurityService {
|
|
389
|
-
|
|
390
|
-
public boolean hasAccess(Long userId) {
|
|
391
|
-
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
|
392
|
-
if (auth == null || !auth.isAuthenticated()) {
|
|
393
|
-
return false;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
UserDetails userDetails = (UserDetails) auth.getPrincipal();
|
|
397
|
-
// Custom logic to check if user has access
|
|
398
|
-
return true;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
public String getCurrentUsername() {
|
|
402
|
-
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
|
403
|
-
if (auth != null && auth.getPrincipal() instanceof UserDetails) {
|
|
404
|
-
return ((UserDetails) auth.getPrincipal()).getUsername();
|
|
405
|
-
}
|
|
406
|
-
return null;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
public boolean hasRole(String role) {
|
|
410
|
-
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
|
411
|
-
return auth != null && auth.getAuthorities().stream()
|
|
412
|
-
.anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals("ROLE_" + role));
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
```
|
|
416
|
-
|
|
417
|
-
## Configuration Properties
|
|
418
|
-
|
|
419
|
-
```yaml
|
|
420
|
-
jwt:
|
|
421
|
-
secret: ${JWT_SECRET:your-256-bit-secret-key-here-change-in-production}
|
|
422
|
-
expiration: 86400000 # 24 hours
|
|
423
|
-
refresh-expiration: 604800000 # 7 days
|
|
424
|
-
|
|
425
|
-
spring:
|
|
426
|
-
security:
|
|
427
|
-
oauth2:
|
|
428
|
-
resourceserver:
|
|
429
|
-
jwt:
|
|
430
|
-
issuer-uri: https://accounts.example.com
|
|
431
|
-
jwk-set-uri: https://accounts.example.com/.well-known/jwks.json
|
|
432
|
-
```
|
|
433
|
-
|
|
434
|
-
## Quick Reference
|
|
435
|
-
|
|
436
|
-
| Annotation | Purpose |
|
|
437
|
-
|-----------|---------|
|
|
438
|
-
| `@EnableWebSecurity` | Enable Spring Security |
|
|
439
|
-
| `@EnableMethodSecurity` | Enable method-level security |
|
|
440
|
-
| `@PreAuthorize` | Check before method execution |
|
|
441
|
-
| `@PostAuthorize` | Check after method execution |
|
|
442
|
-
| `@Secured` | Role-based access control |
|
|
443
|
-
| `@RolesAllowed` | JSR-250 security |
|
|
444
|
-
| `SecurityContextHolder` | Access current security context |
|
|
445
|
-
| `@AuthenticationPrincipal` | Inject current user |
|
|
1
|
+
# Spring Security
|
|
2
|
+
|
|
3
|
+
## Security Configuration
|
|
4
|
+
|
|
5
|
+
```java
|
|
6
|
+
package com.example.infrastructure.security;
|
|
7
|
+
|
|
8
|
+
import lombok.RequiredArgsConstructor;
|
|
9
|
+
import org.springframework.context.annotation.Bean;
|
|
10
|
+
import org.springframework.context.annotation.Configuration;
|
|
11
|
+
import org.springframework.security.authentication.AuthenticationManager;
|
|
12
|
+
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
|
13
|
+
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
|
14
|
+
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
|
15
|
+
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|
16
|
+
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
|
17
|
+
import org.springframework.security.config.http.SessionCreationPolicy;
|
|
18
|
+
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
|
19
|
+
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
20
|
+
import org.springframework.security.web.SecurityFilterChain;
|
|
21
|
+
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
|
22
|
+
|
|
23
|
+
@Configuration
|
|
24
|
+
@EnableWebSecurity
|
|
25
|
+
@EnableMethodSecurity(securedEnabled = true, jsr250Enabled = true)
|
|
26
|
+
@RequiredArgsConstructor
|
|
27
|
+
public class SecurityConfig {
|
|
28
|
+
|
|
29
|
+
private final JwtAuthenticationFilter jwtAuthFilter;
|
|
30
|
+
private final CustomUserDetailsService userDetailsService;
|
|
31
|
+
|
|
32
|
+
@Bean
|
|
33
|
+
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
|
34
|
+
return http
|
|
35
|
+
.csrf(csrf -> csrf.disable())
|
|
36
|
+
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
|
|
37
|
+
.authorizeHttpRequests(auth -> auth
|
|
38
|
+
.requestMatchers("/api/auth/**", "/api/public/**").permitAll()
|
|
39
|
+
.requestMatchers("/actuator/health", "/actuator/info").permitAll()
|
|
40
|
+
.requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll()
|
|
41
|
+
.requestMatchers("/api/admin/**").hasRole("ADMIN")
|
|
42
|
+
.anyRequest().authenticated()
|
|
43
|
+
)
|
|
44
|
+
.sessionManagement(session -> session
|
|
45
|
+
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
|
46
|
+
)
|
|
47
|
+
.authenticationProvider(authenticationProvider())
|
|
48
|
+
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
|
|
49
|
+
.build();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
@Bean
|
|
53
|
+
public DaoAuthenticationProvider authenticationProvider() {
|
|
54
|
+
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
|
55
|
+
provider.setUserDetailsService(userDetailsService);
|
|
56
|
+
provider.setPasswordEncoder(passwordEncoder());
|
|
57
|
+
return provider;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@Bean
|
|
61
|
+
public AuthenticationManager authenticationManager(
|
|
62
|
+
AuthenticationConfiguration config
|
|
63
|
+
) throws Exception {
|
|
64
|
+
return config.getAuthenticationManager();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@Bean
|
|
68
|
+
public PasswordEncoder passwordEncoder() {
|
|
69
|
+
return new BCryptPasswordEncoder(12);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@Bean
|
|
73
|
+
public CorsConfigurationSource corsConfigurationSource() {
|
|
74
|
+
CorsConfiguration configuration = new CorsConfiguration();
|
|
75
|
+
configuration.setAllowedOrigins(List.of("http://localhost:3000"));
|
|
76
|
+
configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
|
|
77
|
+
configuration.setAllowedHeaders(List.of("*"));
|
|
78
|
+
configuration.setAllowCredentials(true);
|
|
79
|
+
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
|
80
|
+
source.registerCorsConfiguration("/**", configuration);
|
|
81
|
+
return source;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## JWT Authentication Filter
|
|
87
|
+
|
|
88
|
+
```java
|
|
89
|
+
package com.example.infrastructure.security;
|
|
90
|
+
|
|
91
|
+
import jakarta.servlet.FilterChain;
|
|
92
|
+
import jakarta.servlet.ServletException;
|
|
93
|
+
import jakarta.servlet.http.HttpServletRequest;
|
|
94
|
+
import jakarta.servlet.http.HttpServletResponse;
|
|
95
|
+
import lombok.RequiredArgsConstructor;
|
|
96
|
+
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
97
|
+
import org.springframework.security.core.context.SecurityContextHolder;
|
|
98
|
+
import org.springframework.security.core.userdetails.UserDetails;
|
|
99
|
+
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
|
100
|
+
import org.springframework.stereotype.Component;
|
|
101
|
+
import org.springframework.web.filter.OncePerRequestFilter;
|
|
102
|
+
|
|
103
|
+
import java.io.IOException;
|
|
104
|
+
|
|
105
|
+
@Component
|
|
106
|
+
@RequiredArgsConstructor
|
|
107
|
+
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
|
108
|
+
|
|
109
|
+
private final JwtService jwtService;
|
|
110
|
+
private final CustomUserDetailsService userDetailsService;
|
|
111
|
+
|
|
112
|
+
@Override
|
|
113
|
+
protected void doFilterInternal(
|
|
114
|
+
HttpServletRequest request,
|
|
115
|
+
HttpServletResponse response,
|
|
116
|
+
FilterChain filterChain
|
|
117
|
+
) throws ServletException, IOException {
|
|
118
|
+
|
|
119
|
+
String authHeader = request.getHeader("Authorization");
|
|
120
|
+
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
|
|
121
|
+
filterChain.doFilter(request, response);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
String jwt = authHeader.substring(7);
|
|
126
|
+
String userEmail = jwtService.extractUsername(jwt);
|
|
127
|
+
|
|
128
|
+
if (userEmail != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
|
129
|
+
UserDetails userDetails = userDetailsService.loadUserByUsername(userEmail);
|
|
130
|
+
|
|
131
|
+
if (jwtService.isTokenValid(jwt, userDetails)) {
|
|
132
|
+
UsernamePasswordAuthenticationToken authToken =
|
|
133
|
+
new UsernamePasswordAuthenticationToken(
|
|
134
|
+
userDetails,
|
|
135
|
+
null,
|
|
136
|
+
userDetails.getAuthorities()
|
|
137
|
+
);
|
|
138
|
+
authToken.setDetails(
|
|
139
|
+
new WebAuthenticationDetailsSource().buildDetails(request)
|
|
140
|
+
);
|
|
141
|
+
SecurityContextHolder.getContext().setAuthentication(authToken);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
filterChain.doFilter(request, response);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## JWT Service
|
|
151
|
+
|
|
152
|
+
```java
|
|
153
|
+
package com.example.infrastructure.security;
|
|
154
|
+
|
|
155
|
+
import io.jsonwebtoken.Claims;
|
|
156
|
+
import io.jsonwebtoken.Jwts;
|
|
157
|
+
import io.jsonwebtoken.SignatureAlgorithm;
|
|
158
|
+
import io.jsonwebtoken.io.Decoders;
|
|
159
|
+
import io.jsonwebtoken.security.Keys;
|
|
160
|
+
import org.springframework.beans.factory.annotation.Value;
|
|
161
|
+
import org.springframework.security.core.userdetails.UserDetails;
|
|
162
|
+
import org.springframework.stereotype.Service;
|
|
163
|
+
|
|
164
|
+
import java.security.Key;
|
|
165
|
+
import java.util.Date;
|
|
166
|
+
import java.util.HashMap;
|
|
167
|
+
import java.util.Map;
|
|
168
|
+
import java.util.function.Function;
|
|
169
|
+
|
|
170
|
+
@Service
|
|
171
|
+
public class JwtService {
|
|
172
|
+
|
|
173
|
+
@Value("${jwt.secret}")
|
|
174
|
+
private String secretKey;
|
|
175
|
+
|
|
176
|
+
@Value("${jwt.expiration}")
|
|
177
|
+
private long jwtExpiration;
|
|
178
|
+
|
|
179
|
+
@Value("${jwt.refresh-expiration}")
|
|
180
|
+
private long refreshExpiration;
|
|
181
|
+
|
|
182
|
+
public String extractUsername(String token) {
|
|
183
|
+
return extractClaim(token, Claims::getSubject);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
|
|
187
|
+
final Claims claims = extractAllClaims(token);
|
|
188
|
+
return claimsResolver.apply(claims);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
public String generateToken(UserDetails userDetails) {
|
|
192
|
+
return generateToken(new HashMap<>(), userDetails);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
public String generateToken(
|
|
196
|
+
Map<String, Object> extraClaims,
|
|
197
|
+
UserDetails userDetails
|
|
198
|
+
) {
|
|
199
|
+
return buildToken(extraClaims, userDetails, jwtExpiration);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
public String generateRefreshToken(UserDetails userDetails) {
|
|
203
|
+
return buildToken(new HashMap<>(), userDetails, refreshExpiration);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
private String buildToken(
|
|
207
|
+
Map<String, Object> extraClaims,
|
|
208
|
+
UserDetails userDetails,
|
|
209
|
+
long expiration
|
|
210
|
+
) {
|
|
211
|
+
return Jwts.builder()
|
|
212
|
+
.setClaims(extraClaims)
|
|
213
|
+
.setSubject(userDetails.getUsername())
|
|
214
|
+
.setIssuedAt(new Date(System.currentTimeMillis()))
|
|
215
|
+
.setExpiration(new Date(System.currentTimeMillis() + expiration))
|
|
216
|
+
.signWith(getSignInKey(), SignatureAlgorithm.HS256)
|
|
217
|
+
.compact();
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
public boolean isTokenValid(String token, UserDetails userDetails) {
|
|
221
|
+
final String username = extractUsername(token);
|
|
222
|
+
return (username.equals(userDetails.getUsername())) && !isTokenExpired(token);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
private boolean isTokenExpired(String token) {
|
|
226
|
+
return extractExpiration(token).before(new Date());
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
private Date extractExpiration(String token) {
|
|
230
|
+
return extractClaim(token, Claims::getExpiration);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
private Claims extractAllClaims(String token) {
|
|
234
|
+
return Jwts.parserBuilder()
|
|
235
|
+
.setSigningKey(getSignInKey())
|
|
236
|
+
.build()
|
|
237
|
+
.parseClaimsJws(token)
|
|
238
|
+
.getBody();
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
private Key getSignInKey() {
|
|
242
|
+
byte[] keyBytes = Decoders.BASE64.decode(secretKey);
|
|
243
|
+
return Keys.hmacShaKeyFor(keyBytes);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## UserDetailsService Implementation
|
|
249
|
+
|
|
250
|
+
```java
|
|
251
|
+
package com.example.infrastructure.security;
|
|
252
|
+
|
|
253
|
+
import com.example.domain.repository.UserRepository;
|
|
254
|
+
import lombok.RequiredArgsConstructor;
|
|
255
|
+
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
|
256
|
+
import org.springframework.security.core.userdetails.UserDetails;
|
|
257
|
+
import org.springframework.security.core.userdetails.UserDetailsService;
|
|
258
|
+
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
|
259
|
+
import org.springframework.stereotype.Service;
|
|
260
|
+
|
|
261
|
+
import java.util.stream.Collectors;
|
|
262
|
+
|
|
263
|
+
@Service
|
|
264
|
+
@RequiredArgsConstructor
|
|
265
|
+
public class CustomUserDetailsService implements UserDetailsService {
|
|
266
|
+
|
|
267
|
+
private final UserRepository userRepository;
|
|
268
|
+
|
|
269
|
+
@Override
|
|
270
|
+
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
|
|
271
|
+
return userRepository.findByEmail(email)
|
|
272
|
+
.map(user -> org.springframework.security.core.userdetails.User.builder()
|
|
273
|
+
.username(user.getEmail())
|
|
274
|
+
.password(user.getPassword())
|
|
275
|
+
.authorities(user.getRoles().stream()
|
|
276
|
+
.map(role -> new SimpleGrantedAuthority(role.getName()))
|
|
277
|
+
.collect(Collectors.toList()))
|
|
278
|
+
.accountExpired(false)
|
|
279
|
+
.accountLocked(!user.getActive())
|
|
280
|
+
.credentialsExpired(false)
|
|
281
|
+
.disabled(!user.getActive())
|
|
282
|
+
.build())
|
|
283
|
+
.orElseThrow(() -> new UsernameNotFoundException("User not found: " + email));
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## Authentication Controller
|
|
289
|
+
|
|
290
|
+
```java
|
|
291
|
+
package com.example.presentation.rest;
|
|
292
|
+
|
|
293
|
+
import com.example.application.dto.AuthRequest;
|
|
294
|
+
import com.example.application.dto.AuthResponse;
|
|
295
|
+
import com.example.application.dto.RegisterRequest;
|
|
296
|
+
import com.example.application.service.AuthenticationService;
|
|
297
|
+
import jakarta.validation.Valid;
|
|
298
|
+
import lombok.RequiredArgsConstructor;
|
|
299
|
+
import org.springframework.http.ResponseEntity;
|
|
300
|
+
import org.springframework.web.bind.annotation.*;
|
|
301
|
+
|
|
302
|
+
@RestController
|
|
303
|
+
@RequestMapping("/api/auth")
|
|
304
|
+
@RequiredArgsConstructor
|
|
305
|
+
public class AuthenticationController {
|
|
306
|
+
|
|
307
|
+
private final AuthenticationService authService;
|
|
308
|
+
|
|
309
|
+
@PostMapping("/register")
|
|
310
|
+
public ResponseEntity<AuthResponse> register(
|
|
311
|
+
@Valid @RequestBody RegisterRequest request
|
|
312
|
+
) {
|
|
313
|
+
return ResponseEntity.ok(authService.register(request));
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
@PostMapping("/login")
|
|
317
|
+
public ResponseEntity<AuthResponse> authenticate(
|
|
318
|
+
@Valid @RequestBody AuthRequest request
|
|
319
|
+
) {
|
|
320
|
+
return ResponseEntity.ok(authService.authenticate(request));
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
@PostMapping("/refresh")
|
|
324
|
+
public ResponseEntity<AuthResponse> refreshToken(
|
|
325
|
+
@RequestHeader("Authorization") String refreshToken
|
|
326
|
+
) {
|
|
327
|
+
return ResponseEntity.ok(authService.refreshToken(refreshToken));
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
## Method-Level Security
|
|
333
|
+
|
|
334
|
+
```java
|
|
335
|
+
package com.example.application.service;
|
|
336
|
+
|
|
337
|
+
import lombok.RequiredArgsConstructor;
|
|
338
|
+
import org.springframework.security.access.prepost.PreAuthorize;
|
|
339
|
+
import org.springframework.security.access.prepost.PostAuthorize;
|
|
340
|
+
import org.springframework.stereotype.Service;
|
|
341
|
+
|
|
342
|
+
@Service
|
|
343
|
+
@RequiredArgsConstructor
|
|
344
|
+
public class UserService {
|
|
345
|
+
|
|
346
|
+
private final UserRepository userRepository;
|
|
347
|
+
|
|
348
|
+
@PreAuthorize("hasRole('ADMIN')")
|
|
349
|
+
public List<User> getAllUsers() {
|
|
350
|
+
return userRepository.findAll();
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
@PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
|
|
354
|
+
public User getUserById(Long id) {
|
|
355
|
+
return userRepository.findById(id)
|
|
356
|
+
.orElseThrow(() -> new EntityNotFoundException("User not found"));
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
@PreAuthorize("#user.id == authentication.principal.id or hasRole('ADMIN')")
|
|
360
|
+
public User updateUser(User user) {
|
|
361
|
+
return userRepository.save(user);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
@PostAuthorize("returnObject.email == authentication.principal.username or hasRole('ADMIN')")
|
|
365
|
+
public User findUserByEmail(String email) {
|
|
366
|
+
return userRepository.findByEmail(email)
|
|
367
|
+
.orElseThrow(() -> new EntityNotFoundException("User not found"));
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
@PreAuthorize("@userSecurityService.hasAccess(#userId)")
|
|
371
|
+
public void deleteUser(Long userId) {
|
|
372
|
+
userRepository.deleteById(userId);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
## Security Utilities
|
|
378
|
+
|
|
379
|
+
```java
|
|
380
|
+
package com.example.infrastructure.security;
|
|
381
|
+
|
|
382
|
+
import org.springframework.security.core.Authentication;
|
|
383
|
+
import org.springframework.security.core.context.SecurityContextHolder;
|
|
384
|
+
import org.springframework.security.core.userdetails.UserDetails;
|
|
385
|
+
import org.springframework.stereotype.Component;
|
|
386
|
+
|
|
387
|
+
@Component("userSecurityService")
|
|
388
|
+
public class UserSecurityService {
|
|
389
|
+
|
|
390
|
+
public boolean hasAccess(Long userId) {
|
|
391
|
+
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
|
392
|
+
if (auth == null || !auth.isAuthenticated()) {
|
|
393
|
+
return false;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
UserDetails userDetails = (UserDetails) auth.getPrincipal();
|
|
397
|
+
// Custom logic to check if user has access
|
|
398
|
+
return true;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
public String getCurrentUsername() {
|
|
402
|
+
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
|
403
|
+
if (auth != null && auth.getPrincipal() instanceof UserDetails) {
|
|
404
|
+
return ((UserDetails) auth.getPrincipal()).getUsername();
|
|
405
|
+
}
|
|
406
|
+
return null;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
public boolean hasRole(String role) {
|
|
410
|
+
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
|
411
|
+
return auth != null && auth.getAuthorities().stream()
|
|
412
|
+
.anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals("ROLE_" + role));
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
## Configuration Properties
|
|
418
|
+
|
|
419
|
+
```yaml
|
|
420
|
+
jwt:
|
|
421
|
+
secret: ${JWT_SECRET:your-256-bit-secret-key-here-change-in-production}
|
|
422
|
+
expiration: 86400000 # 24 hours
|
|
423
|
+
refresh-expiration: 604800000 # 7 days
|
|
424
|
+
|
|
425
|
+
spring:
|
|
426
|
+
security:
|
|
427
|
+
oauth2:
|
|
428
|
+
resourceserver:
|
|
429
|
+
jwt:
|
|
430
|
+
issuer-uri: https://accounts.example.com
|
|
431
|
+
jwk-set-uri: https://accounts.example.com/.well-known/jwks.json
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
## Quick Reference
|
|
435
|
+
|
|
436
|
+
| Annotation | Purpose |
|
|
437
|
+
|-----------|---------|
|
|
438
|
+
| `@EnableWebSecurity` | Enable Spring Security |
|
|
439
|
+
| `@EnableMethodSecurity` | Enable method-level security |
|
|
440
|
+
| `@PreAuthorize` | Check before method execution |
|
|
441
|
+
| `@PostAuthorize` | Check after method execution |
|
|
442
|
+
| `@Secured` | Role-based access control |
|
|
443
|
+
| `@RolesAllowed` | JSR-250 security |
|
|
444
|
+
| `SecurityContextHolder` | Access current security context |
|
|
445
|
+
| `@AuthenticationPrincipal` | Inject current user |
|