@venizia/ignis-docs 0.2.0 → 0.2.1-1
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/README.md +14 -14
- package/content/best-practices/api-usage-examples.md +39 -19
- package/content/best-practices/architectural-patterns.md +24 -13
- package/content/best-practices/architecture-decisions.md +29 -16
- package/content/best-practices/code-style-standards/advanced-patterns.md +43 -31
- package/content/best-practices/code-style-standards/constants-configuration.md +19 -4
- package/content/best-practices/code-style-standards/control-flow.md +33 -1
- package/content/best-practices/code-style-standards/documentation.md +28 -8
- package/content/best-practices/code-style-standards/function-patterns.md +15 -4
- package/content/best-practices/code-style-standards/index.md +7 -2
- package/content/best-practices/code-style-standards/naming-conventions.md +27 -3
- package/content/best-practices/code-style-standards/route-definitions.md +9 -5
- package/content/best-practices/code-style-standards/tooling.md +14 -1
- package/content/best-practices/code-style-standards/type-safety.md +39 -6
- package/content/best-practices/common-pitfalls.md +59 -35
- package/content/best-practices/contribution-workflow.md +8 -4
- package/content/best-practices/data-modeling.md +78 -62
- package/content/best-practices/deployment-strategies.md +56 -19
- package/content/best-practices/error-handling.md +247 -153
- package/content/best-practices/index.md +6 -0
- package/content/best-practices/performance-optimization.md +26 -13
- package/content/best-practices/security-guidelines.md +35 -9
- package/content/best-practices/testing-strategies.md +7 -2
- package/content/best-practices/troubleshooting-tips.md +27 -17
- package/content/extensions/components/api-reference.md +109 -323
- package/content/extensions/components/authentication/api.md +489 -602
- package/content/extensions/components/authentication/errors.md +135 -498
- package/content/extensions/components/authentication/index.md +89 -801
- package/content/extensions/components/authentication/usage.md +231 -955
- package/content/extensions/components/authorization/api.md +991 -644
- package/content/extensions/components/authorization/errors.md +204 -208
- package/content/extensions/components/authorization/getting-started.md +227 -0
- package/content/extensions/components/authorization/index.md +88 -795
- package/content/extensions/components/authorization/usage.md +219 -528
- package/content/extensions/components/health-check.md +77 -243
- package/content/extensions/components/index.md +24 -90
- package/content/extensions/components/mail/api.md +553 -285
- package/content/extensions/components/mail/errors.md +76 -62
- package/content/extensions/components/mail/index.md +111 -463
- package/content/extensions/components/mail/usage.md +139 -173
- package/content/extensions/components/request-tracker.md +70 -173
- package/content/extensions/components/socket-io/api.md +462 -785
- package/content/extensions/components/socket-io/errors.md +49 -51
- package/content/extensions/components/socket-io/index.md +69 -372
- package/content/extensions/components/socket-io/usage.md +212 -105
- package/content/extensions/components/static-asset/api.md +461 -141
- package/content/extensions/components/static-asset/errors.md +121 -53
- package/content/extensions/components/static-asset/index.md +84 -606
- package/content/extensions/components/static-asset/usage.md +184 -299
- package/content/extensions/components/template/index.md +3 -3
- package/content/extensions/components/websocket/api.md +311 -404
- package/content/extensions/components/websocket/errors.md +47 -56
- package/content/extensions/components/websocket/index.md +75 -407
- package/content/extensions/components/websocket/usage.md +120 -338
- package/content/extensions/helpers/cron/index.md +52 -160
- package/content/extensions/helpers/crypto/index.md +67 -480
- package/content/extensions/helpers/crypto/reference.md +528 -0
- package/content/extensions/helpers/env/index.md +64 -178
- package/content/extensions/helpers/error/index.md +286 -196
- package/content/extensions/helpers/index.md +61 -47
- package/content/extensions/helpers/inversion/index.md +76 -550
- package/content/extensions/helpers/inversion/reference.md +530 -0
- package/content/extensions/helpers/kafka/admin.md +23 -3
- package/content/extensions/helpers/kafka/compile-binary.md +83 -52
- package/content/extensions/helpers/kafka/consumer.md +65 -28
- package/content/extensions/helpers/kafka/examples.md +46 -253
- package/content/extensions/helpers/kafka/index.md +55 -617
- package/content/extensions/helpers/kafka/producer.md +156 -22
- package/content/extensions/helpers/kafka/schema-registry.md +59 -79
- package/content/extensions/helpers/logger/hf-logger.md +220 -0
- package/content/extensions/helpers/logger/index.md +78 -552
- package/content/extensions/helpers/logger/pino.md +105 -0
- package/content/extensions/helpers/logger/reference.md +937 -0
- package/content/extensions/helpers/network/api.md +276 -195
- package/content/extensions/helpers/network/index.md +87 -524
- package/content/extensions/helpers/queue/index.md +80 -897
- package/content/extensions/helpers/queue/reference.md +494 -0
- package/content/extensions/helpers/redis/index.md +86 -640
- package/content/extensions/helpers/redis/reference.md +784 -0
- package/content/extensions/helpers/secrets/index.md +136 -0
- package/content/extensions/helpers/socket-io/api.md +325 -204
- package/content/extensions/helpers/socket-io/index.md +79 -429
- package/content/extensions/helpers/storage/api.md +584 -464
- package/content/extensions/helpers/storage/index.md +80 -573
- package/content/extensions/helpers/types/index.md +75 -495
- package/content/extensions/helpers/types/reference.md +689 -0
- package/content/extensions/helpers/uid/index.md +176 -189
- package/content/extensions/helpers/websocket/api.md +366 -214
- package/content/extensions/helpers/websocket/index.md +68 -503
- package/content/extensions/helpers/worker-thread/index.md +62 -396
- package/content/extensions/helpers/worker-thread/reference.md +428 -0
- package/content/extensions/index.md +38 -39
- package/content/extensions/src-details/mcp-server.md +96 -548
- package/content/guides/core-concepts/persistent/datasources.md +2 -2
- package/content/guides/core-concepts/persistent/index.md +5 -1
- package/content/guides/core-concepts/persistent/models.md +1 -1
- package/content/guides/core-concepts/persistent/pglite.md +218 -0
- package/content/guides/core-concepts/persistent/postgres-drivers.md +21 -15
- package/content/guides/core-concepts/persistent/search-meilisearch.md +22 -12
- package/content/guides/core-concepts/persistent/search-typesense.md +28 -16
- package/content/guides/core-concepts/persistent/sqlite.md +296 -0
- package/content/guides/core-concepts/persistent/transactions.md +12 -11
- package/content/guides/core-concepts/secrets-vault.md +177 -0
- package/content/guides/core-concepts/services.md +1 -1
- package/content/guides/get-started/5-minute-quickstart.md +59 -206
- package/content/guides/get-started/philosophy.md +135 -670
- package/content/guides/get-started/setup.md +53 -74
- package/content/guides/migrations/redis-helpers-migration.md +5 -4
- package/content/guides/migrations/scoped-rbac-migration.md +5 -5
- package/content/guides/migrations/unified-connectors-migration.md +8 -7
- package/content/guides/tutorials/ecommerce-api.md +3 -8
- package/content/guides/tutorials/realtime-chat.md +1 -1
- package/content/references/base/application.md +64 -22
- package/content/references/base/components.md +3 -3
- package/content/references/base/connectors.md +79 -136
- package/content/references/base/controllers.md +12 -12
- package/content/references/base/datasources-reference.md +600 -0
- package/content/references/base/datasources.md +84 -444
- package/content/references/base/dependency-injection.md +25 -46
- package/content/references/base/filter-system/application-usage.md +95 -123
- package/content/references/base/filter-system/array-operators.md +33 -43
- package/content/references/base/filter-system/comparison-operators.md +55 -63
- package/content/references/base/filter-system/default-filter.md +144 -350
- package/content/references/base/filter-system/fields-order-pagination.md +116 -148
- package/content/references/base/filter-system/index.md +114 -253
- package/content/references/base/filter-system/json-filtering.md +52 -181
- package/content/references/base/filter-system/list-operators.md +28 -44
- package/content/references/base/filter-system/logical-operators.md +69 -114
- package/content/references/base/filter-system/null-operators.md +41 -98
- package/content/references/base/filter-system/pattern-matching.md +48 -51
- package/content/references/base/filter-system/quick-reference.md +93 -196
- package/content/references/base/filter-system/range-operators.md +22 -38
- package/content/references/base/filter-system/tips.md +70 -133
- package/content/references/base/filter-system/use-cases.md +173 -232
- package/content/references/base/grpc-controllers.md +53 -17
- package/content/references/base/index.md +5 -3
- package/content/references/base/middlewares.md +43 -28
- package/content/references/base/models-reference.md +886 -0
- package/content/references/base/models.md +81 -1452
- package/content/references/base/providers.md +8 -8
- package/content/references/base/repositories/advanced.md +281 -419
- package/content/references/base/repositories/index.md +84 -644
- package/content/references/base/repositories/mixins.md +25 -21
- package/content/references/base/repositories/relations.md +194 -375
- package/content/references/base/repositories/soft-deletable.md +67 -55
- package/content/references/base/secrets.md +267 -0
- package/content/references/base/services.md +8 -6
- package/content/references/configuration/environment-variables.md +73 -21
- package/content/references/configuration/index.md +51 -31
- package/content/references/index.md +1 -1
- package/content/references/quick-reference.md +3 -16
- package/content/references/utilities/crypto.md +35 -76
- package/content/references/utilities/date.md +33 -73
- package/content/references/utilities/duration.md +85 -0
- package/content/references/utilities/index.md +6 -2
- package/content/references/utilities/jsx-reference.md +298 -0
- package/content/references/utilities/jsx.md +82 -525
- package/content/references/utilities/module.md +81 -61
- package/content/references/utilities/parse.md +34 -64
- package/content/references/utilities/performance.md +33 -58
- package/content/references/utilities/promise.md +28 -62
- package/content/references/utilities/request.md +58 -218
- package/content/references/utilities/retry.md +139 -0
- package/content/references/utilities/schema.md +43 -137
- package/content/references/utilities/statuses-reference.md +361 -0
- package/content/references/utilities/statuses.md +63 -667
- package/dist/mcp-server/index.js +0 -0
- package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.js +3 -3
- package/dist/mcp-server/tools/github/search-code.tool.js +1 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.js +1 -1
- package/dist/mcp-server/tools/github/view-source-file.tool.js +1 -1
- package/package.json +24 -23
|
@@ -1,7 +1,19 @@
|
|
|
1
|
-
# Authorization
|
|
1
|
+
# Authorization - Error Reference
|
|
2
2
|
|
|
3
3
|
> Complete error messages and troubleshooting for the authorization module. See [Setup & Configuration](./) for initial setup.
|
|
4
4
|
|
|
5
|
+
## Find what you need
|
|
6
|
+
|
|
7
|
+
| You want to | Go to |
|
|
8
|
+
|---|---|
|
|
9
|
+
| See every error message, status code, and cause in one table | [Complete Error Reference](#complete-error-reference) |
|
|
10
|
+
| See which pipeline step throws which error | [Error Flow Diagram](#error-flow-diagram) |
|
|
11
|
+
| Fix a specific error message you're staring at | [Troubleshooting](#troubleshooting) |
|
|
12
|
+
| Debug "authorization does nothing" during rollout | [Authorization is not running](#authorization-is-not-running) |
|
|
13
|
+
| Debug rules rebuilding when you expected a cache hit | [Rules are rebuilt on every request](#rules-are-rebuilt-on-every-request) |
|
|
14
|
+
| Debug policies that don't seem to load | [Casbin policies not loading](#casbin-policies-not-loading) |
|
|
15
|
+
| Debug a Redis cache that never hits | [Redis cache not working](#redis-cache-not-working) |
|
|
16
|
+
|
|
5
17
|
## Error Flow Diagram
|
|
6
18
|
|
|
7
19
|
```mermaid
|
|
@@ -16,93 +28,102 @@ flowchart TD
|
|
|
16
28
|
S4 -->|DENY| E403a[/"403: Authorization denied by voter"/]
|
|
17
29
|
S4 -->|ALLOW/ABSTAIN| S5{"Step 5: Enforcers registered?"}
|
|
18
30
|
|
|
19
|
-
S5 -->|No enforcers| OK3([No error -
|
|
31
|
+
S5 -->|No enforcers, defaultDecision: allow| OK3([No error - allow, warning logged])
|
|
32
|
+
S5 -->|No enforcers, defaultDecision: deny or unset| E403c[/"403: no enforcer registered"/]
|
|
20
33
|
S5 -->|Yes| S5b{"Resolve enforcer"}
|
|
21
|
-
S5b -->|Name not found|
|
|
22
|
-
S5b -->|DI fails|
|
|
34
|
+
S5b -->|Name not found| E400b[/"400: Descriptor not found"/]
|
|
35
|
+
S5b -->|DI fails| E400c[/"400: Failed to resolve"/]
|
|
23
36
|
S5b -->|OK| S6{"Step 6: Build rules"}
|
|
24
37
|
|
|
25
|
-
S6 -->|Not configured|
|
|
26
|
-
S6 -->|No FilteredAdapter|
|
|
27
|
-
S6 -->|Empty Redis key|
|
|
38
|
+
S6 -->|Not configured| E400d[/"400: Not configured. Call configure() first."/]
|
|
39
|
+
S6 -->|No FilteredAdapter| E400e[/"400: Adapter does not support loadFilteredPolicy"/]
|
|
40
|
+
S6 -->|Empty Redis key| E400f[/"400: keyFn returned an empty cache key"/]
|
|
41
|
+
S6 -->|No principalType| E400g[/"400: principalType is required"/]
|
|
28
42
|
S6 -->|OK| S7{"Step 7: Evaluate"}
|
|
29
43
|
|
|
30
|
-
S7 -->|No action/resource|
|
|
44
|
+
S7 -->|No action/resource| E400h[/"400: action and resource required"/]
|
|
31
45
|
S7 -->|ALLOW| OK4([Authorized])
|
|
32
|
-
S7 -->|DENY| E403b[/"403: Authorization denied"/]
|
|
46
|
+
S7 -->|DENY / ABSTAIN-as-deny| E403b[/"403: Authorization denied"/]
|
|
47
|
+
|
|
48
|
+
style E401 fill:#f8d7da,stroke:#dc3545
|
|
49
|
+
style E403a fill:#f8d7da,stroke:#dc3545
|
|
50
|
+
style E403b fill:#f8d7da,stroke:#dc3545
|
|
51
|
+
style E403c fill:#f8d7da,stroke:#dc3545
|
|
52
|
+
style E400b fill:#fff3cd,stroke:#ffc107
|
|
53
|
+
style E400c fill:#fff3cd,stroke:#ffc107
|
|
54
|
+
style E400d fill:#fff3cd,stroke:#ffc107
|
|
55
|
+
style E400e fill:#fff3cd,stroke:#ffc107
|
|
56
|
+
style E400f fill:#fff3cd,stroke:#ffc107
|
|
57
|
+
style E400g fill:#fff3cd,stroke:#ffc107
|
|
58
|
+
style E400h fill:#fff3cd,stroke:#ffc107
|
|
33
59
|
```
|
|
34
60
|
|
|
35
61
|
## Complete Error Reference
|
|
36
62
|
|
|
37
|
-
All error messages from the authorization module, organized by source
|
|
63
|
+
All error messages from the authorization module, organized by source. **Status** is what `error.statusCode` holds. Most calls use `getError({ message })` with no explicit `statusCode`, so the shared `ApplicationError` defaults it to **400**. Only the request-pipeline errors below (steps 2, 4, 7) set an explicit `401`/`403`.
|
|
64
|
+
|
|
65
|
+
### Component Errors (`AuthorizeComponent`)
|
|
66
|
+
|
|
67
|
+
Thrown during `binding()`, at application startup.
|
|
68
|
+
|
|
69
|
+
| Error Message | Status | Method | Cause |
|
|
70
|
+
|---------------|--------|--------|-------|
|
|
71
|
+
| `[AuthorizeComponent] No authorize options found. Bind options to AuthorizeBindingKeys.OPTIONS before registering the component.` | 400 | `binding` | `IAuthorizeOptions` was never bound before `this.component(AuthorizeComponent)` |
|
|
72
|
+
|
|
73
|
+
### Enforcer Registry Errors (`AuthorizationEnforcerRegistry` + inherited `AbstractAuthRegistry`)
|
|
74
|
+
|
|
75
|
+
| Error Message | Status | Method | Cause |
|
|
76
|
+
|---------------|--------|--------|-------|
|
|
77
|
+
| <code v-pre>[getKey] Invalid name | name: {{name}}</code> | 400 | `getKey` | Enforcer name is empty or falsy |
|
|
78
|
+
| `[AuthorizationEnforcerRegistry] No items registered` | 400 | `getDefaultName` | `getDefaultEnforcerName()` called with zero enforcers registered |
|
|
79
|
+
| <code v-pre>[AuthorizationEnforcerRegistry] Duplicate enforcer name(s): {{names}}</code> | 400 | `register` | Two or more enforcers in the same `register()` call share a name |
|
|
80
|
+
| <code v-pre>[AuthorizationEnforcerRegistry] Enforcer already registered: {{name}}</code> | 400 | `register` | An enforcer with this name was already registered in a previous call |
|
|
81
|
+
| <code v-pre>[AuthorizationEnforcerRegistry] Descriptor not found: {{name}}</code> | 400 | `resolveDescriptor` | `enforcerName` doesn't match any registered enforcer |
|
|
82
|
+
| <code v-pre>[AuthorizationEnforcerRegistry] Failed to resolve: {{name}}</code> | 400 | `resolveDescriptor` | The registered class has unsatisfied `@inject` dependencies |
|
|
83
|
+
| <code v-pre>[AuthorizationEnforcerRegistry] Enforcer "{{name}}" does not support cache invalidation</code> | 400 | `invalidateUserCache` / `rebuildUserCache` | The resolved enforcer doesn't implement the optional cache-management methods |
|
|
38
84
|
|
|
39
|
-
|
|
85
|
+
> [!NOTE]
|
|
86
|
+
> `[AuthorizationEnforcerRegistry] No items registered` can only surface if `getDefaultEnforcerName()` is called directly. During normal middleware execution, the provider checks `registry.hasEnforcers()` first and denies (or, with `defaultDecision: 'allow'`, proceeds) before ever calling `getDefaultEnforcerName()`, so it never reaches this throw.
|
|
40
87
|
|
|
41
|
-
|
|
42
|
-
|---------------|--------|--------|
|
|
43
|
-
| `[AuthorizeComponent] No authorize options found. Bind options to AuthorizeBindingKeys.OPTIONS before registering the component.` | 500 | `binding` |
|
|
88
|
+
### Authorization Provider Errors (`AuthorizationProvider` - the request pipeline)
|
|
44
89
|
|
|
45
|
-
|
|
90
|
+
The only errors in the module with an **explicit** `statusCode`.
|
|
46
91
|
|
|
47
|
-
| Error Message | Status |
|
|
48
|
-
|
|
49
|
-
| `Authorization failed: No authenticated user found` | 401 |
|
|
50
|
-
|
|
|
51
|
-
| <code v-pre>Authorization
|
|
52
|
-
|
|
|
92
|
+
| Error Message | Status | Pipeline step | Cause |
|
|
93
|
+
|---------------|--------|------|-------|
|
|
94
|
+
| `Authorization failed: No authenticated user found` | 401 | 2 - User check | `Authentication.CURRENT_USER` is missing from the Hono context |
|
|
95
|
+
| <code v-pre>Authorization denied by voter | action: {{action}} | resource: {{resource}}</code> | 403 | 4 - Voters | A voter function returned `AuthorizationDecisions.DENY` |
|
|
96
|
+
| <code v-pre>Authorization failed: authorize() was declared for this route but no enforcer is registered | path: {{path}}</code> | 403 | 5 - Resolve enforcer | `hasEnforcers()` is `false` and `defaultDecision` is `'deny'` (the default) or unset |
|
|
97
|
+
| `Authorization failed: user.principalType is required for enforcer-based authorization` | 400 | 6 - Build rules | The authenticated user object has no `principalType` field |
|
|
98
|
+
| <code v-pre>Authorization denied | action: {{action}} | resource: {{resource}}</code> | 403 | 7 - Evaluate | The enforcer returned `DENY`, or `ABSTAIN` and `defaultDecision` resolved to `'deny'` |
|
|
53
99
|
|
|
54
|
-
### Enforcer
|
|
100
|
+
### Casbin Enforcer Errors - Startup (`CasbinAuthorizationEnforcer.configure()`)
|
|
55
101
|
|
|
56
|
-
| Error Message | Status | Method |
|
|
57
|
-
|
|
58
|
-
|
|
|
59
|
-
| `[
|
|
60
|
-
| <code v-pre>[
|
|
61
|
-
| <code v-pre>[
|
|
62
|
-
| <code v-pre>[
|
|
63
|
-
| <code v-pre>[
|
|
102
|
+
| Error Message | Status | Method | Cause |
|
|
103
|
+
|---------------|--------|--------|-------|
|
|
104
|
+
| `[CasbinAuthorizationEnforcer] "casbin" is not installed` | 400 | `configure` | The optional `casbin` peer dependency isn't installed |
|
|
105
|
+
| `[CasbinAuthorizationEnforcer] options.model is required.` | 400 | `configure` | `model` is missing from the enforcer options |
|
|
106
|
+
| <code v-pre>[registerMatchers] Role definition "{{name}}" is not declared in the Casbin model. Declare it under [role_definition] (e.g. `g = _, _, _`) before enabling domainMatching.</code> | 400 | `configure` (via `registerMatchers`) | `domainMatching.roleDefinition` isn't declared in `[role_definition]` (only checked when `domainMatching` is set) |
|
|
107
|
+
| <code v-pre>[CasbinAuthorizationEnforcer] Matcher smoke test failed at warmup - the model matcher did not compile ... {{error}}</code> | 400 | `configure` (via `assertMatcherCompilesSync`) | The matcher expression doesn't compile: syntax error, an unregistered function, or an arity mismatch |
|
|
108
|
+
| <code v-pre>[CasbinAuthorizationEnforcer] cached.options.expiresIn must be >= 10000 (ms) | Received: {{value}}</code> | 400 | `configure` (via `validateExpiresIn`) | `cached.options.expiresIn` is below `MIN_EXPIRES_IN` (10,000 ms) |
|
|
109
|
+
| <code v-pre>[resolveDomainMatchingFn] Unsupported func: {{name}} | Valids: [...]</code> | 400 | `configure` (via `registerMatchers`) | `domainMatching.fn` isn't a `CasbinDomainMatchingFunctions` value |
|
|
110
|
+
| <code v-pre>[resolveModel] Invalid model.driver | Valids: [file, text]</code> | 400 | `configure` (via `resolveModel`) | `model.driver` isn't `'file'` or `'text'` |
|
|
64
111
|
|
|
65
112
|
> [!NOTE]
|
|
66
|
-
>
|
|
67
|
-
|
|
68
|
-
### Casbin Enforcer Errors (
|
|
69
|
-
|
|
70
|
-
| Error Message | Status | Method |
|
|
71
|
-
|
|
72
|
-
| `[CasbinAuthorizationEnforcer]
|
|
73
|
-
| `[CasbinAuthorizationEnforcer]
|
|
74
|
-
| `[CasbinAuthorizationEnforcer]
|
|
75
|
-
| `[
|
|
76
|
-
| `[
|
|
77
|
-
| `[
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
| <code v-pre>[resolveDomainMatchingFn] Unsupported func: {{name}} | Valids: [...]</code> | 500 | `configure` (via `registerMatchers`) |
|
|
81
|
-
| <code v-pre>[registerMatchers] Role definition "{{name}}" is not declared in the Casbin model. ...</code> | 500 | `configure` (via `registerMatchers`, only when `domainMatching` is set) |
|
|
82
|
-
| <code v-pre>[resolveModel] Invalid model.driver | Valids: [file, text]</code> | 500 | `configure` (via `resolveModel`) |
|
|
83
|
-
| `[CasbinAuthorizationEnforcer] Cache management requires the redis cache driver, but caching is disabled.` | 500 | `invalidateUserCache`/`rebuildUserCache` (via `requireRedisCache`) |
|
|
84
|
-
|
|
85
|
-
> The `Invalid cached.driver` errors were removed - `cached` is now a typed union
|
|
86
|
-
> (`{ use: false } | { use: true, driver: 'redis', ... }`), so an invalid driver is a compile-time
|
|
87
|
-
> error, not a runtime one.
|
|
88
|
-
|
|
89
|
-
### Policy Loading Errors (CasbinAuthorizationEnforcer internals)
|
|
90
|
-
|
|
91
|
-
| Error Message | Status | Method |
|
|
92
|
-
|---------------|--------|--------|
|
|
93
|
-
| `[CasbinAuthorizationEnforcer] keyFn returned an empty cache key.` | 400 | `resolveCacheKey` (read + cache-management paths) |
|
|
94
|
-
| `[extractUserLines] Adapter does not support loadFilteredPolicy.` | 500 | `extractUserLines` |
|
|
95
|
-
| `[loadPolicyLinesIntoModel] Not configured. Call configure() first.` | 500 | `loadPolicyLinesIntoModel` |
|
|
96
|
-
| `[CasbinAuthorizationEnforcer] Cached payload is not an array of policy lines.` | - (logged, not thrown) | `parseCachedPolicyLines` - corrupt entry is discarded + refetched |
|
|
97
|
-
|
|
98
|
-
> A corrupted Redis cache entry does **not** raise an error - it is logged and discarded, and the
|
|
99
|
-
> lines are refetched from the adapter (the request never 500s on cache corruption).
|
|
100
|
-
|
|
101
|
-
### Registry Errors (AuthorizationEnforcerRegistry)
|
|
102
|
-
|
|
103
|
-
| Error Message | Status | Method |
|
|
104
|
-
|---------------|--------|--------|
|
|
105
|
-
| `[AuthorizationEnforcerRegistry] Enforcer "{{name}}" does not support cache invalidation` | 500 | `invalidateUserCache` / `rebuildUserCache` (the resolved enforcer lacks the optional method) |
|
|
113
|
+
> `cached` is a typed discriminated union (`{ use: false } | { use: true; driver: 'redis'; ... }`), so an unsupported cache driver fails at compile time - there is no `Invalid cached.driver` runtime error. Caching is **Redis-only**.
|
|
114
|
+
|
|
115
|
+
### Casbin Enforcer Errors - Runtime (`buildRules` / `evaluate` / cache management)
|
|
116
|
+
|
|
117
|
+
| Error Message | Status | Method | Cause |
|
|
118
|
+
|---------------|--------|--------|-------|
|
|
119
|
+
| `[CasbinAuthorizationEnforcer] Not configured. Call configure() first.` | 400 | `evaluate` | `evaluate()` ran before `configure()` built the enforcer pool - should not happen via `resolveEnforcer()` |
|
|
120
|
+
| `[CasbinAuthorizationEnforcer] request.action and request.resource are required.` | 400 | `evaluate` | Malformed `IAuthorizationRequest` passed to `evaluate()` |
|
|
121
|
+
| `[CasbinAuthorizationEnforcer] keyFn returned an empty cache key.` | 400 | `resolveCacheKey` (via `buildRules`, `invalidateUserCache`, `rebuildUserCache`) | `cached.options.keyFn` returned a falsy value for this user |
|
|
122
|
+
| `[CasbinAuthorizationEnforcer] Cache management requires the redis cache driver, but caching is disabled.` | 400 | `invalidateUserCache` / `rebuildUserCache` (via `requireRedisCache`) | Called with `cached: { use: false }` |
|
|
123
|
+
| `[extractUserLines] Adapter does not support loadFilteredPolicy.` | 400 | `buildRules` (via `extractUserLines`) | `options.adapter` doesn't implement casbin's `FilteredAdapter.loadFilteredPolicy` |
|
|
124
|
+
| `[loadPolicyLinesIntoModel] Not configured. Call configure() first.` | 400 | `evaluate` (via `loadPolicyLinesIntoModel`) | Same root cause as the `evaluate` "Not configured" row, different call site |
|
|
125
|
+
|
|
126
|
+
**Not an error** - `[CasbinAuthorizationEnforcer] Cached payload is not an array of policy lines.` `parseCachedPolicyLines` logs this at `warn` level; it never throws up to the caller. A corrupted or legacy Redis entry is discarded, and the lines are refetched from the adapter. The request never 500s (or 400s) on cache corruption.
|
|
106
127
|
|
|
107
128
|
## Troubleshooting
|
|
108
129
|
|
|
@@ -110,85 +131,85 @@ All error messages from the authorization module, organized by source:
|
|
|
110
131
|
|
|
111
132
|
**Cause:** `AuthorizeComponent` was registered but `IAuthorizeOptions` was not bound to the container.
|
|
112
133
|
|
|
113
|
-
**Fix:** Bind options **before** registering the component
|
|
134
|
+
**Fix:** Bind options **before** registering the component.
|
|
114
135
|
|
|
115
136
|
```typescript
|
|
116
|
-
// 1. Bind options first
|
|
117
137
|
this.bind<IAuthorizeOptions>({ key: AuthorizeBindingKeys.OPTIONS }).toValue({
|
|
118
138
|
defaultDecision: 'deny',
|
|
119
139
|
alwaysAllowRoles: ['999_super-admin'],
|
|
120
140
|
});
|
|
121
141
|
|
|
122
|
-
// 2. Then register the component
|
|
123
142
|
this.component(AuthorizeComponent);
|
|
124
143
|
```
|
|
125
144
|
|
|
126
145
|
### "Authorization failed: No authenticated user found"
|
|
127
146
|
|
|
128
|
-
**Cause:** The authorization middleware runs after authentication, but no user was found on the context (`Authentication.CURRENT_USER` is undefined).
|
|
129
|
-
- The route has `authorize` but no `authenticate` config
|
|
130
|
-
- Authentication middleware failed silently
|
|
131
|
-
- Authentication was skipped but authorization was not
|
|
147
|
+
**Cause:** The authorization middleware runs after authentication, but no user was found on the context (`Authentication.CURRENT_USER` is `undefined`). Common triggers:
|
|
132
148
|
|
|
133
|
-
|
|
149
|
+
- The route has `authorize` but no `authenticate`.
|
|
150
|
+
- Authentication was skipped, but authorization wasn't.
|
|
151
|
+
- The request genuinely has no valid credentials.
|
|
152
|
+
|
|
153
|
+
**Fix:** Every route with `authorize` needs a matching `authenticate` config.
|
|
134
154
|
|
|
135
155
|
```typescript
|
|
136
156
|
this.defineRoute({
|
|
137
157
|
configs: {
|
|
138
158
|
path: '/',
|
|
139
159
|
method: 'get',
|
|
140
|
-
authenticate: { strategies: [Authentication.STRATEGY_JWT] }, //
|
|
160
|
+
authenticate: { strategies: [Authentication.STRATEGY_JWT] }, // must be present
|
|
141
161
|
authorize: { action: AuthorizationActions.READ, resource: 'Article' },
|
|
142
162
|
// ...
|
|
143
163
|
},
|
|
144
|
-
handler: async
|
|
164
|
+
handler: async context => { /* ... */ },
|
|
145
165
|
});
|
|
146
166
|
```
|
|
147
167
|
|
|
148
168
|
### "Authorization failed: user.principalType is required"
|
|
149
169
|
|
|
150
|
-
**Cause:** The authenticated user object
|
|
170
|
+
**Cause:** The authenticated user object has no `principalType` field. Enforcer-based authorization uses it to build the casbin subject - for example, `User_123`.
|
|
151
171
|
|
|
152
|
-
**Fix:**
|
|
172
|
+
**Fix:** Set `principalType` when you build the user in your authentication service or token payload.
|
|
153
173
|
|
|
154
174
|
```typescript
|
|
155
|
-
// In your JWT token service or authentication service:
|
|
156
175
|
return {
|
|
157
176
|
userId: '123',
|
|
158
|
-
principalType: '
|
|
177
|
+
principalType: 'User', // required for authorization
|
|
159
178
|
roles: [...],
|
|
160
179
|
};
|
|
161
180
|
```
|
|
162
181
|
|
|
163
182
|
> [!NOTE]
|
|
164
|
-
> `principalType` is
|
|
183
|
+
> `principalType` is read via the `IAuthUser` index signature, not a dedicated field - it must be a real property on the returned user object.
|
|
165
184
|
|
|
166
185
|
### "Authorization denied by voter | action: ... | resource: ..."
|
|
167
186
|
|
|
168
|
-
**Cause:** A voter function explicitly returned `AuthorizationDecisions.DENY
|
|
187
|
+
**Cause:** A voter function explicitly returned `AuthorizationDecisions.DENY`.
|
|
188
|
+
|
|
189
|
+
**Fix:** Inspect the voter named in your logs. Common causes:
|
|
169
190
|
|
|
170
|
-
|
|
171
|
-
-
|
|
172
|
-
-
|
|
173
|
-
- Voter checking resource state (e.g., locked, archived)
|
|
191
|
+
- An ownership check failed.
|
|
192
|
+
- A time-window check rejected the request.
|
|
193
|
+
- A resource-state check (locked/archived) blocked it.
|
|
174
194
|
|
|
175
195
|
### "Authorization denied | action: ... | resource: ..."
|
|
176
196
|
|
|
177
|
-
**Cause:**
|
|
178
|
-
|
|
179
|
-
-
|
|
180
|
-
-
|
|
197
|
+
**Cause:** `enforcer.evaluate()` returned `DENY`, or `ABSTAIN` and it fell back to `defaultDecision`. Usually one of:
|
|
198
|
+
|
|
199
|
+
- No matching policy for the user.
|
|
200
|
+
- A matching `deny` policy.
|
|
201
|
+
- The model doesn't cover the requested domain/resource/action combination.
|
|
181
202
|
|
|
182
|
-
**Fix:**
|
|
203
|
+
**Fix:** Work through this checklist:
|
|
204
|
+
|
|
205
|
+
1. **Policies are loaded correctly** - verify the adapter returns the right rows for this user (`ScopedCasbinAdapter` reads `PolicyDefinition` filtered by `subject_type`/`subject_id`).
|
|
206
|
+
2. **Subject format matches.** `normalizePayloadFn` (or the default scoped payload) must produce a subject that matches what's stored - for example, `User_123`.
|
|
207
|
+
3. **The model covers the request.** For a custom (non-scoped) `.conf`, confirm the matcher handles the action/resource/domain shape you're sending.
|
|
208
|
+
4. **Set `defaultDecision` explicitly** - don't rely on an implicit fallback:
|
|
183
209
|
|
|
184
|
-
1. **Policies are loaded correctly** -- verify your adapter is returning the right policy definitions for the user
|
|
185
|
-
2. **Subject format matches** -- the `normalizePayloadFn` must produce subjects matching your policy definitions (e.g., `user_123` must match what's in the database)
|
|
186
|
-
3. **Casbin model covers the request** -- your `.conf` file must define matchers for the action/resource/domain pattern you're using
|
|
187
|
-
4. **Set defaultDecision explicitly:**
|
|
188
210
|
```typescript
|
|
189
211
|
this.bind<IAuthorizeOptions>({ key: AuthorizeBindingKeys.OPTIONS }).toValue({
|
|
190
|
-
defaultDecision: 'deny',
|
|
191
|
-
// ...
|
|
212
|
+
defaultDecision: 'deny', // explicit is better than implicit
|
|
192
213
|
});
|
|
193
214
|
```
|
|
194
215
|
|
|
@@ -196,108 +217,89 @@ this.bind<IAuthorizeOptions>({ key: AuthorizeBindingKeys.OPTIONS }).toValue({
|
|
|
196
217
|
|
|
197
218
|
**Cause:** Two or more enforcers in the same `register()` call have the same name.
|
|
198
219
|
|
|
199
|
-
**Fix:**
|
|
220
|
+
**Fix:** Give every enforcer in the call a unique name.
|
|
200
221
|
|
|
201
222
|
```typescript
|
|
202
223
|
AuthorizationEnforcerRegistry.getInstance().register({
|
|
203
224
|
container: this,
|
|
204
225
|
enforcers: [
|
|
205
|
-
{ enforcer:
|
|
206
|
-
{ enforcer:
|
|
226
|
+
{ enforcer: CasbinAuthorizationEnforcer, name: 'casbin', type: 'casbin', options: { /* ... */ } },
|
|
227
|
+
{ enforcer: MyCustomEnforcer, name: 'custom', type: 'custom' }, // different name
|
|
207
228
|
],
|
|
208
229
|
});
|
|
209
230
|
```
|
|
210
231
|
|
|
211
232
|
### "[AuthorizationEnforcerRegistry] Enforcer already registered: ..."
|
|
212
233
|
|
|
213
|
-
**Cause:** An enforcer with this name was already registered in a previous `register()` call
|
|
214
|
-
|
|
215
|
-
**Fix:** Ensure you only register each enforcer name once. If you need to re-register, call `registry.reset()` first (typically only in tests).
|
|
216
|
-
|
|
217
|
-
### "[AuthorizationEnforcerRegistry] No items registered"
|
|
218
|
-
|
|
219
|
-
**Cause:** Tried to get the default enforcer name but no enforcers are registered. This error can only occur if `getDefaultEnforcerName()` is called directly. During normal middleware execution, the provider checks `registry.hasEnforcers()` first and skips authorization if no enforcers are registered, so this error is not triggered in the standard pipeline.
|
|
234
|
+
**Cause:** An enforcer with this name was already registered in a previous `register()` call - the registry doesn't allow overwriting.
|
|
220
235
|
|
|
221
|
-
**Fix:** Register
|
|
222
|
-
|
|
223
|
-
```typescript
|
|
224
|
-
// 1. Bind options and register component
|
|
225
|
-
this.bind<IAuthorizeOptions>({ key: AuthorizeBindingKeys.OPTIONS }).toValue({ ... });
|
|
226
|
-
this.component(AuthorizeComponent);
|
|
227
|
-
|
|
228
|
-
// 2. Register enforcers
|
|
229
|
-
AuthorizationEnforcerRegistry.getInstance().register({
|
|
230
|
-
container: this,
|
|
231
|
-
enforcers: [{ enforcer: CasbinAuthorizationEnforcer, name: 'casbin', type: 'casbin', options: { ... } }],
|
|
232
|
-
});
|
|
233
|
-
```
|
|
236
|
+
**Fix:** Register each name once. Call `AuthorizationEnforcerRegistry.getInstance().reset()` first if you genuinely need to re-register (typically only in tests).
|
|
234
237
|
|
|
235
238
|
### "[AuthorizationEnforcerRegistry] Descriptor not found: ..."
|
|
236
239
|
|
|
237
|
-
**Cause:**
|
|
240
|
+
**Cause:** `enforcerName` in an `authorize()` call doesn't match any registered enforcer name.
|
|
238
241
|
|
|
239
|
-
**Fix:**
|
|
242
|
+
**Fix:** Match the name used in `register()`. The default (when `enforcerName` is omitted) is the first one registered.
|
|
240
243
|
|
|
241
244
|
### "[AuthorizationEnforcerRegistry] Failed to resolve: ..."
|
|
242
245
|
|
|
243
|
-
**Cause:** The enforcer class
|
|
246
|
+
**Cause:** The enforcer class is registered, but DI resolution returned `null` - typically an unsatisfied `@inject` dependency in its constructor.
|
|
244
247
|
|
|
245
|
-
**Fix:**
|
|
248
|
+
**Fix:** Confirm every `@inject` in the enforcer's constructor is bound in the same container before `resolveEnforcer()` runs.
|
|
246
249
|
|
|
247
|
-
### "[CasbinAuthorizationEnforcer] casbin is not installed"
|
|
250
|
+
### "[CasbinAuthorizationEnforcer] "casbin" is not installed"
|
|
248
251
|
|
|
249
|
-
**Cause:** The Casbin enforcer dynamically imports `casbin`
|
|
252
|
+
**Cause:** The Casbin enforcer dynamically imports `casbin` in `configure()`, but the package isn't installed.
|
|
250
253
|
|
|
251
|
-
**Fix:**
|
|
254
|
+
**Fix:**
|
|
252
255
|
|
|
253
256
|
```bash
|
|
254
257
|
bun add casbin
|
|
255
258
|
```
|
|
256
259
|
|
|
257
|
-
### "[CasbinAuthorizationEnforcer] options.model is required"
|
|
260
|
+
### "[CasbinAuthorizationEnforcer] options.model is required."
|
|
258
261
|
|
|
259
|
-
**Cause:** The
|
|
262
|
+
**Cause:** The enforcer options have no `model`.
|
|
260
263
|
|
|
261
|
-
**Fix:** Provide
|
|
264
|
+
**Fix:** Provide a model - inline text (recommended: `CASBIN_RBAC_DOMAIN_SCOPED_MODEL`) or a file path.
|
|
262
265
|
|
|
263
266
|
```typescript
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
options: {
|
|
271
|
-
model: {
|
|
272
|
-
driver: 'file',
|
|
273
|
-
definition: path.resolve(__dirname, './security/model.conf'),
|
|
274
|
-
},
|
|
275
|
-
cached: { use: false },
|
|
276
|
-
},
|
|
277
|
-
}],
|
|
278
|
-
});
|
|
267
|
+
options: {
|
|
268
|
+
model: { driver: CasbinEnforcerModelDrivers.TEXT, definition: CASBIN_RBAC_DOMAIN_SCOPED_MODEL },
|
|
269
|
+
isScoped: true,
|
|
270
|
+
adapter,
|
|
271
|
+
cached: { use: false },
|
|
272
|
+
}
|
|
279
273
|
```
|
|
280
274
|
|
|
281
|
-
### "[
|
|
275
|
+
### "[registerMatchers] Role definition "g2" is not declared in the Casbin model..."
|
|
282
276
|
|
|
283
|
-
**Cause:**
|
|
277
|
+
**Cause:** `domainMatching.roleDefinition` references a relation the model doesn't declare under `[role_definition]`. Without this check, Casbin would register the function as a silent no-op, leaving wildcard domains permanently unmatched - global roles would be silently denied. The enforcer throws at boot instead.
|
|
284
278
|
|
|
285
|
-
**Fix:**
|
|
279
|
+
**Fix:** Point `roleDefinition` at a relation the model actually declares.
|
|
286
280
|
|
|
287
281
|
```typescript
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
const adapter = new ScopedCasbinAdapter({
|
|
291
|
-
dataSource,
|
|
292
|
-
entities: { /* IScopedCasbinEntities */ },
|
|
293
|
-
});
|
|
282
|
+
domainMatching: { roleDefinition: 'g', fn: CasbinDomainMatchingFunctions.KEY_MATCH } // model must declare `g = _, _, _`
|
|
294
283
|
```
|
|
295
284
|
|
|
285
|
+
### "[CasbinAuthorizationEnforcer] Matcher smoke test failed at warmup..."
|
|
286
|
+
|
|
287
|
+
**Cause:** `assertMatcherCompilesSync()` runs a dummy `enforceSync()` at warmup to force casbin's lazy matcher compile. It failed for one of these reasons:
|
|
288
|
+
|
|
289
|
+
- A matcher syntax error.
|
|
290
|
+
- A function referenced in the matcher that was never registered.
|
|
291
|
+
- A request-arity mismatch (3 vs. 4 tokens).
|
|
292
|
+
|
|
293
|
+
**Fix:** Check the `[matchers]` section of your `.conf`.
|
|
294
|
+
|
|
295
|
+
- Scoped model: confirm `isScoped: true` is set. It registers `objectMatch` and `keyMatch` automatically.
|
|
296
|
+
- Custom flat model: confirm every function the matcher calls is registered via `domainMatching`.
|
|
297
|
+
|
|
296
298
|
### "[CasbinAuthorizationEnforcer] cached.options.expiresIn must be >= 10000"
|
|
297
299
|
|
|
298
|
-
**Cause:**
|
|
300
|
+
**Cause:** `expiresIn` is below the 10,000 ms minimum (`MIN_EXPIRES_IN`).
|
|
299
301
|
|
|
300
|
-
**Fix:**
|
|
302
|
+
**Fix:**
|
|
301
303
|
|
|
302
304
|
```typescript
|
|
303
305
|
cached: {
|
|
@@ -305,53 +307,42 @@ cached: {
|
|
|
305
307
|
driver: 'redis',
|
|
306
308
|
options: {
|
|
307
309
|
connection: redisHelper,
|
|
308
|
-
expiresIn: 5 * 60 * 1000,
|
|
309
|
-
keyFn: ({ user }) => `authz:policies:${user.userId}`,
|
|
310
|
+
expiresIn: 5 * 60 * 1000, // 5 minutes (minimum: 10,000 ms)
|
|
311
|
+
keyFn: ({ user }) => `authz:policies:${user.principalType}:${user.userId}`,
|
|
310
312
|
},
|
|
311
313
|
},
|
|
312
314
|
```
|
|
313
315
|
|
|
314
316
|
### "[CasbinAuthorizationEnforcer] Not configured. Call configure() first."
|
|
315
317
|
|
|
316
|
-
**Cause:**
|
|
318
|
+
**Cause:** `evaluate()` (or its internal `loadPolicyLinesIntoModel()`) ran before `configure()` built the enforcer pool. This shouldn't happen through `resolveEnforcer()`, which auto-configures. It can occur if the enforcer is resolved manually from the DI container.
|
|
317
319
|
|
|
318
|
-
**Fix:** Always
|
|
320
|
+
**Fix:** Always go through the registry, which handles configure-once automatically.
|
|
319
321
|
|
|
320
322
|
```typescript
|
|
321
323
|
const enforcer = await AuthorizationEnforcerRegistry.getInstance().resolveEnforcer({ name: 'casbin' });
|
|
322
|
-
// configure() is called automatically on first resolve
|
|
323
324
|
```
|
|
324
325
|
|
|
325
|
-
### "[
|
|
326
|
+
### "[CasbinAuthorizationEnforcer] keyFn returned an empty cache key."
|
|
326
327
|
|
|
327
|
-
**Cause:**
|
|
328
|
+
**Cause:** `cached.options.keyFn` returned a falsy value for a user.
|
|
328
329
|
|
|
329
|
-
**Fix:**
|
|
330
|
+
**Fix:** Always return a stable, non-empty key.
|
|
330
331
|
|
|
331
332
|
```typescript
|
|
332
|
-
keyFn: ({ user }) => {
|
|
333
|
-
if (!user.userId) {
|
|
334
|
-
throw new Error('User ID is required for cache key');
|
|
335
|
-
}
|
|
336
|
-
return `authz:policies:${user.userId}`;
|
|
337
|
-
},
|
|
333
|
+
keyFn: ({ user }) => `authz:policies:${user.principalType}:${user.userId}`,
|
|
338
334
|
```
|
|
339
335
|
|
|
340
|
-
### "[
|
|
341
|
-
|
|
342
|
-
**Cause:** `evaluate()` or `loadPolicyLinesIntoModel()` ran before the enforcer pool was built.
|
|
343
|
-
|
|
344
|
-
**Fix:** Ensure `configure()` completed successfully (the registry calls it on first use) before any
|
|
345
|
-
evaluation. The enforcer pool is created in `configure()`.
|
|
346
|
-
|
|
347
|
-
### "[CasbinAuthorizationEnforcer] keyFn returned an empty cache key."
|
|
336
|
+
### "[extractUserLines] Adapter does not support loadFilteredPolicy"
|
|
348
337
|
|
|
349
|
-
**Cause:**
|
|
338
|
+
**Cause:** `options.adapter` doesn't implement casbin's `FilteredAdapter.loadFilteredPolicy`. Authorization always loads policies filtered by principal.
|
|
350
339
|
|
|
351
|
-
**Fix:**
|
|
340
|
+
**Fix:** Use `ScopedCasbinAdapter`, or extend `BaseFilteredAdapter` and implement `loadFilteredPolicy`.
|
|
352
341
|
|
|
353
342
|
```typescript
|
|
354
|
-
|
|
343
|
+
import { ScopedCasbinAdapter } from '@venizia/ignis';
|
|
344
|
+
|
|
345
|
+
const adapter = new ScopedCasbinAdapter({ dataSource, entities: { /* IScopedCasbinEntities */ } });
|
|
355
346
|
```
|
|
356
347
|
|
|
357
348
|
### "[resolveModel] Invalid model.driver | Valids: [file, text]"
|
|
@@ -360,39 +351,44 @@ keyFn: ({ user }) => `authz:policies:${user.principalType}:${user.userId}`,
|
|
|
360
351
|
|
|
361
352
|
**Fix:** Use `CasbinEnforcerModelDrivers.FILE` (`'file'`) or `CasbinEnforcerModelDrivers.TEXT` (`'text'`).
|
|
362
353
|
|
|
363
|
-
|
|
364
|
-
|
|
354
|
+
### "[CasbinAuthorizationEnforcer] Cache management requires the redis cache driver, but caching is disabled."
|
|
355
|
+
|
|
356
|
+
**Cause:** `invalidateUserCache()` or `rebuildUserCache()` was called on an enforcer configured with `cached: { use: false }`.
|
|
357
|
+
|
|
358
|
+
**Fix:** Either configure Redis caching, or don't call the cache-management methods for a non-cached enforcer.
|
|
365
359
|
|
|
366
360
|
## Common Patterns
|
|
367
361
|
|
|
368
|
-
### Authorization
|
|
362
|
+
### Authorization is not running
|
|
363
|
+
|
|
364
|
+
Check, in order:
|
|
365
|
+
|
|
366
|
+
1. `authorize` is actually set on the route config (not just `authenticate`).
|
|
367
|
+
2. `authenticate` isn't `{ skip: true }` - that skips authorization too, in both raw route configs and the CRUD factory.
|
|
368
|
+
3. The component is registered AND at least one enforcer is registered via `AuthorizationEnforcerRegistry`.
|
|
369
|
+
4. If no enforcers are registered, the middleware denies with a 403 naming the missing enforcer - unless `defaultDecision: 'allow'` is set, in which case it proceeds and logs a warning. A warning in your logs on every request is often the real sign of "no enforcer registered" during rollout.
|
|
369
370
|
|
|
370
|
-
|
|
371
|
-
1. Verify `authorize` is set on the route config (not just `authenticate`)
|
|
372
|
-
2. Verify `authenticate` is not set to `{ skip: true }` (which also skips authorization in CRUD factory)
|
|
373
|
-
3. Verify the component is registered and enforcers are registered via the registry
|
|
374
|
-
4. Note: if no enforcers are registered, the middleware skips authorization silently (calls `next()`) rather than throwing an error
|
|
371
|
+
### Rules are rebuilt on every request
|
|
375
372
|
|
|
376
|
-
|
|
373
|
+
Rules cache on `Authorization.RULES`, but only **within one request**:
|
|
377
374
|
|
|
378
|
-
|
|
379
|
-
-
|
|
380
|
-
-
|
|
381
|
-
- If rules are `undefined` or `null`, they will be rebuilt
|
|
375
|
+
- A new HTTP request always starts with an empty cache.
|
|
376
|
+
- Multiple `authorize` specs on the same route share the cache - only the first builds.
|
|
377
|
+
- `undefined`/`null` on `Authorization.RULES` triggers a rebuild - `c.set(Authorization.RULES, null)` forces one mid-request.
|
|
382
378
|
|
|
383
|
-
### Casbin
|
|
379
|
+
### Casbin policies not loading
|
|
384
380
|
|
|
385
|
-
1. **
|
|
386
|
-
2. **
|
|
387
|
-
3. **
|
|
388
|
-
4. **
|
|
381
|
+
1. **Adapter entities** - `IScopedCasbinEntities` (`policyDefinition`/`permission` table + schema names, `principals`, `domainTypes`) must match your actual database schema.
|
|
382
|
+
2. **Variant column** - `PolicyDefinition.variant` must use `AuthorizationPolicyVariants.*.action` values: `grant`, `assign_role`, `join_domain`, `role_inherits`, `resource_inherits`, `action_inherits`, `domain_inherits`.
|
|
383
|
+
3. **Subject/target types** - the adapter's SQL filters by `subject_type`/`target_type` against `principals` and `domainTypes`; a mismatch silently returns zero rows.
|
|
384
|
+
4. **Model** - scoped RBAC needs `CASBIN_RBAC_DOMAIN_SCOPED_MODEL` with `isScoped: true` together; one without the other misfires.
|
|
389
385
|
|
|
390
|
-
### Redis
|
|
386
|
+
### Redis cache not working
|
|
391
387
|
|
|
392
|
-
1. **
|
|
393
|
-
2.
|
|
394
|
-
3.
|
|
395
|
-
4. **
|
|
388
|
+
1. **Connection** - verify the `IRedisHelper` (`RedisSingleHelper`/`RedisClusterHelper`/`RedisSentinelHelper`) is actually connected.
|
|
389
|
+
2. **`keyFn`** - must return a unique, non-empty key per user.
|
|
390
|
+
3. **`expiresIn`** - must be `>= 10_000` (`MIN_EXPIRES_IN`).
|
|
391
|
+
4. **Corruption is silent.** A malformed cached payload is discarded and refetched (see the Casbin runtime error table above). If caching never seems to hit, suspect a `keyFn` mismatch before corruption.
|
|
396
392
|
|
|
397
393
|
## See Also
|
|
398
394
|
|