@chill-sharp/ui-core 1.1.12
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/.agents/skills/chillsharp-current-user-preferences/SKILL.md +70 -0
- package/.agents/skills/chillsharp-ui-template/SKILL.md +18 -0
- package/README.md +103 -0
- package/chill-sharp-ui-core.d.ts.map +1 -0
- package/doc/AIAssistedDevelopment/README.md +185 -0
- package/doc/AttachmentModel/README.md +173 -0
- package/doc/AuthenticationModel/README.md +213 -0
- package/doc/AuthenticationModel/how-to-integreate-auth-minimal-api.md +293 -0
- package/doc/ChillSharpClient.md +464 -0
- package/doc/ClientGeneration/README.md +172 -0
- package/doc/ComplianceGuide/README.md +178 -0
- package/doc/Configuration/README.md +94 -0
- package/doc/CurrentUserPreferences.md +114 -0
- package/doc/DateTimePolicy/README.md +154 -0
- package/doc/DateTimeSerialization.md +423 -0
- package/doc/Endpoints.md +260 -0
- package/doc/HowTo/01-simple-blog-sqlite.md +153 -0
- package/doc/HowTo/02-blog-schema-labels.md +140 -0
- package/doc/HowTo/03-authentication.md +218 -0
- package/doc/HowTo/04-blog-posts-one-to-many.md +194 -0
- package/doc/HowTo/05-docker-env-variables.md +274 -0
- package/doc/HowTo/06-chunk-transactions-autocomplete.md +196 -0
- package/doc/Mcp/ChatGPT.md +291 -0
- package/doc/Mcp/README.md +799 -0
- package/doc/MenuGuide/README.md +49 -0
- package/doc/ModelPreparation.md +255 -0
- package/doc/PermissionModel/README.md +277 -0
- package/doc/README.md +228 -0
- package/doc/ReferenceExistence.md +130 -0
- package/doc/RegisterContext.md +217 -0
- package/doc/UiCore/CRUD.md +170 -0
- package/doc/UiCore/README.md +13 -0
- package/doc/ValidationModel/README.md +117 -0
- package/doc/it/AIAssistedDevelopment/README.md +185 -0
- package/doc/it/AttachmentModel/README.md +173 -0
- package/doc/it/AuthenticationModel/README.md +171 -0
- package/doc/it/AuthenticationModel/how-to-integreate-auth-minimal-api.md +292 -0
- package/doc/it/ChillSharpClient.md +464 -0
- package/doc/it/ClientGeneration/README.md +152 -0
- package/doc/it/ComplianceGuide/README.md +178 -0
- package/doc/it/Configuration/README.md +94 -0
- package/doc/it/CurrentUserPreferences.md +114 -0
- package/doc/it/DateTimePolicy/README.md +154 -0
- package/doc/it/DateTimeSerialization.md +423 -0
- package/doc/it/Endpoints.md +260 -0
- package/doc/it/HowTo/01-simple-blog-sqlite.md +152 -0
- package/doc/it/HowTo/02-blog-schema-labels.md +139 -0
- package/doc/it/HowTo/03-authentication.md +221 -0
- package/doc/it/HowTo/04-blog-posts-one-to-many.md +193 -0
- package/doc/it/HowTo/05-docker-env-variables.md +268 -0
- package/doc/it/HowTo/06-chunk-transactions-autocomplete.md +196 -0
- package/doc/it/Mcp/ChatGPT.md +291 -0
- package/doc/it/Mcp/README.md +799 -0
- package/doc/it/MenuGuide/README.md +49 -0
- package/doc/it/ModelPreparation.md +254 -0
- package/doc/it/PermissionModel/README.md +190 -0
- package/doc/it/README.md +172 -0
- package/doc/it/ReferenceExistence.md +130 -0
- package/doc/it/RegisterContext.md +218 -0
- package/doc/it/UiCore/CRUD.md +170 -0
- package/doc/it/UiCore/README.md +13 -0
- package/doc/it/ValidationModel/README.md +117 -0
- package/fesm2022/chill-sharp-ui-core.mjs +16725 -0
- package/fesm2022/chill-sharp-ui-core.mjs.map +1 -0
- package/index.d.ts +6 -0
- package/lib/chill-sharp-ui-root.component.d.ts +6 -0
- package/lib/chill-sharp-ui-root.component.d.ts.map +1 -0
- package/lib/chill-sharp-ui.routes.d.ts +3 -0
- package/lib/chill-sharp-ui.routes.d.ts.map +1 -0
- package/lib/chill.config.d.ts +5 -0
- package/lib/chill.config.d.ts.map +1 -0
- package/lib/layouts/auth-shell.component.d.ts +8 -0
- package/lib/layouts/auth-shell.component.d.ts.map +1 -0
- package/lib/layouts/workspace-page.component.d.ts +49 -0
- package/lib/layouts/workspace-page.component.d.ts.map +1 -0
- package/lib/lib/chill-form.component.d.ts +151 -0
- package/lib/lib/chill-form.component.d.ts.map +1 -0
- package/lib/lib/chill-i18n-button-label.component.d.ts +27 -0
- package/lib/lib/chill-i18n-button-label.component.d.ts.map +1 -0
- package/lib/lib/chill-i18n-label.component.d.ts +30 -0
- package/lib/lib/chill-i18n-label.component.d.ts.map +1 -0
- package/lib/lib/chill-json-input.component.d.ts +31 -0
- package/lib/lib/chill-json-input.component.d.ts.map +1 -0
- package/lib/lib/chill-polymorphic-input-controls/chill-polymorphic-boolean-control.component.d.ts +12 -0
- package/lib/lib/chill-polymorphic-input-controls/chill-polymorphic-boolean-control.component.d.ts.map +1 -0
- package/lib/lib/chill-polymorphic-input-controls/chill-polymorphic-editor-control.component.d.ts +17 -0
- package/lib/lib/chill-polymorphic-input-controls/chill-polymorphic-editor-control.component.d.ts.map +1 -0
- package/lib/lib/chill-polymorphic-input-controls/chill-polymorphic-lookup-control.component.d.ts +45 -0
- package/lib/lib/chill-polymorphic-input-controls/chill-polymorphic-lookup-control.component.d.ts.map +1 -0
- package/lib/lib/chill-polymorphic-input-controls/chill-polymorphic-scalar-control.component.d.ts +19 -0
- package/lib/lib/chill-polymorphic-input-controls/chill-polymorphic-scalar-control.component.d.ts.map +1 -0
- package/lib/lib/chill-polymorphic-input-controls/chill-polymorphic-select-control.component.d.ts +12 -0
- package/lib/lib/chill-polymorphic-input-controls/chill-polymorphic-select-control.component.d.ts.map +1 -0
- package/lib/lib/chill-polymorphic-input-controls/chill-polymorphic-textarea-control.component.d.ts +13 -0
- package/lib/lib/chill-polymorphic-input-controls/chill-polymorphic-textarea-control.component.d.ts.map +1 -0
- package/lib/lib/chill-polymorphic-input.component.d.ts +452 -0
- package/lib/lib/chill-polymorphic-input.component.d.ts.map +1 -0
- package/lib/lib/chill-polymorphic-output-controls/chill-polymorphic-output-boolean-control.component.d.ts +7 -0
- package/lib/lib/chill-polymorphic-output-controls/chill-polymorphic-output-boolean-control.component.d.ts.map +1 -0
- package/lib/lib/chill-polymorphic-output-controls/chill-polymorphic-output-lookup-control.component.d.ts +7 -0
- package/lib/lib/chill-polymorphic-output-controls/chill-polymorphic-output-lookup-control.component.d.ts.map +1 -0
- package/lib/lib/chill-polymorphic-output-controls/chill-polymorphic-output-number-control.component.d.ts +7 -0
- package/lib/lib/chill-polymorphic-output-controls/chill-polymorphic-output-number-control.component.d.ts.map +1 -0
- package/lib/lib/chill-polymorphic-output-controls/chill-polymorphic-output-temporal-control.component.d.ts +8 -0
- package/lib/lib/chill-polymorphic-output-controls/chill-polymorphic-output-temporal-control.component.d.ts.map +1 -0
- package/lib/lib/chill-polymorphic-output-controls/chill-polymorphic-output-value-control.component.d.ts +7 -0
- package/lib/lib/chill-polymorphic-output-controls/chill-polymorphic-output-value-control.component.d.ts.map +1 -0
- package/lib/lib/chill-polymorphic-output.component.d.ts +75 -0
- package/lib/lib/chill-polymorphic-output.component.d.ts.map +1 -0
- package/lib/lib/chill-table.component.d.ts +434 -0
- package/lib/lib/chill-table.component.d.ts.map +1 -0
- package/lib/lib/chill-text-editor-dialog.component.d.ts +14 -0
- package/lib/lib/chill-text-editor-dialog.component.d.ts.map +1 -0
- package/lib/lib/crud-configuration.utils.d.ts +4 -0
- package/lib/lib/crud-configuration.utils.d.ts.map +1 -0
- package/lib/lib/culture-name-options.d.ts +3 -0
- package/lib/lib/culture-name-options.d.ts.map +1 -0
- package/lib/lib/date-format-options.d.ts +3 -0
- package/lib/lib/date-format-options.d.ts.map +1 -0
- package/lib/lib/iana-time-zone-options.d.ts +3 -0
- package/lib/lib/iana-time-zone-options.d.ts.map +1 -0
- package/lib/lib/notice-transition.directive.d.ts +17 -0
- package/lib/lib/notice-transition.directive.d.ts.map +1 -0
- package/lib/lib/schema-property-dialog.component.d.ts +74 -0
- package/lib/lib/schema-property-dialog.component.d.ts.map +1 -0
- package/lib/models/chill-auth.models.d.ts +176 -0
- package/lib/models/chill-auth.models.d.ts.map +1 -0
- package/lib/models/chill-menu.models.d.ts +12 -0
- package/lib/models/chill-menu.models.d.ts.map +1 -0
- package/lib/models/chill-schema.models.d.ts +141 -0
- package/lib/models/chill-schema.models.d.ts.map +1 -0
- package/lib/models/workspace-dialog.models.d.ts +16 -0
- package/lib/models/workspace-dialog.models.d.ts.map +1 -0
- package/lib/models/workspace-task.models.d.ts +36 -0
- package/lib/models/workspace-task.models.d.ts.map +1 -0
- package/lib/pages/confirm-reset-page.component.d.ts +21 -0
- package/lib/pages/confirm-reset-page.component.d.ts.map +1 -0
- package/lib/pages/crud/attachment-upload-dialog.component.d.ts +24 -0
- package/lib/pages/crud/attachment-upload-dialog.component.d.ts.map +1 -0
- package/lib/pages/crud/crud-page.component.d.ts +244 -0
- package/lib/pages/crud/crud-page.component.d.ts.map +1 -0
- package/lib/pages/login-page.component.d.ts +21 -0
- package/lib/pages/login-page.component.d.ts.map +1 -0
- package/lib/pages/permissions/auth-role-dialog.component.d.ts +29 -0
- package/lib/pages/permissions/auth-role-dialog.component.d.ts.map +1 -0
- package/lib/pages/permissions/auth-search-select.component.d.ts +28 -0
- package/lib/pages/permissions/auth-search-select.component.d.ts.map +1 -0
- package/lib/pages/permissions/auth-user-dialog.component.d.ts +35 -0
- package/lib/pages/permissions/auth-user-dialog.component.d.ts.map +1 -0
- package/lib/pages/permissions/permission-editor.component.d.ts +55 -0
- package/lib/pages/permissions/permission-editor.component.d.ts.map +1 -0
- package/lib/pages/permissions/permissions-page.component.d.ts +38 -0
- package/lib/pages/permissions/permissions-page.component.d.ts.map +1 -0
- package/lib/pages/permissions/role-permission.component.d.ts +43 -0
- package/lib/pages/permissions/role-permission.component.d.ts.map +1 -0
- package/lib/pages/permissions/user-permission.component.d.ts +43 -0
- package/lib/pages/permissions/user-permission.component.d.ts.map +1 -0
- package/lib/pages/register-page.component.d.ts +24 -0
- package/lib/pages/register-page.component.d.ts.map +1 -0
- package/lib/pages/reset-password-page.component.d.ts +18 -0
- package/lib/pages/reset-password-page.component.d.ts.map +1 -0
- package/lib/provide-chill-sharp-ui-core.d.ts +8 -0
- package/lib/provide-chill-sharp-ui-core.d.ts.map +1 -0
- package/lib/services/chill.service.d.ts +249 -0
- package/lib/services/chill.service.d.ts.map +1 -0
- package/lib/services/workspace-dialog.service.d.ts +22 -0
- package/lib/services/workspace-dialog.service.d.ts.map +1 -0
- package/lib/services/workspace-layout.service.d.ts +13 -0
- package/lib/services/workspace-layout.service.d.ts.map +1 -0
- package/lib/services/workspace-task-registry.service.d.ts +35 -0
- package/lib/services/workspace-task-registry.service.d.ts.map +1 -0
- package/lib/services/workspace-toolbar.service.d.ts +23 -0
- package/lib/services/workspace-toolbar.service.d.ts.map +1 -0
- package/lib/services/workspace.service.d.ts +114 -0
- package/lib/services/workspace.service.d.ts.map +1 -0
- package/lib/storage-keys.d.ts +5 -0
- package/lib/storage-keys.d.ts.map +1 -0
- package/lib/tasks/crud-task/crud-task.component.d.ts +33 -0
- package/lib/tasks/crud-task/crud-task.component.d.ts.map +1 -0
- package/lib/tasks/goto-url-task/goto-url-task.component.d.ts +31 -0
- package/lib/tasks/goto-url-task/goto-url-task.component.d.ts.map +1 -0
- package/lib/workspace/confirm-message-dialog.component.d.ts +16 -0
- package/lib/workspace/confirm-message-dialog.component.d.ts.map +1 -0
- package/lib/workspace/entity-options-dialog.component.d.ts +29 -0
- package/lib/workspace/entity-options-dialog.component.d.ts.map +1 -0
- package/lib/workspace/external-task-api.d.ts +2 -0
- package/lib/workspace/external-task-api.d.ts.map +1 -0
- package/lib/workspace/user-profile-dialog.component.d.ts +30 -0
- package/lib/workspace/user-profile-dialog.component.d.ts.map +1 -0
- package/lib/workspace/workspace-dialog-host.component.d.ts +26 -0
- package/lib/workspace/workspace-dialog-host.component.d.ts.map +1 -0
- package/lib/workspace/workspace-menu-item-dialog.component.d.ts +61 -0
- package/lib/workspace/workspace-menu-item-dialog.component.d.ts.map +1 -0
- package/lib/workspace/workspace-menu.component.d.ts +104 -0
- package/lib/workspace/workspace-menu.component.d.ts.map +1 -0
- package/lib/workspace/workspace-taskbar.component.d.ts +14 -0
- package/lib/workspace/workspace-taskbar.component.d.ts.map +1 -0
- package/package.json +54 -0
- package/public-api.d.ts +56 -0
- package/public-api.d.ts.map +1 -0
- package/service-worker/chill-sharp-service-worker.js +166 -0
- package/styles/core-theme.scss +1268 -0
- package/template-customization/upgrade.ps1.template +342 -0
- package/template-customization/upgrade.sh.template +271 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# ChillSharp Authentication And Authorization
|
|
2
|
+
|
|
3
|
+
Versione italiana: [Italiano](../it/AuthenticationModel/README.md)
|
|
4
|
+
|
|
5
|
+
This document covers the auth module at a reference level. For a guided setup, keep using [doc/HowTo/03-authentication.md](../HowTo/03-authentication.md).
|
|
6
|
+
|
|
7
|
+
## Module Split
|
|
8
|
+
|
|
9
|
+
`ChillSharp.Auth` exposes two related but distinct concerns:
|
|
10
|
+
|
|
11
|
+
- account authentication
|
|
12
|
+
ASP.NET Core Identity-backed register, login, refresh, password-change, and password-reset flows
|
|
13
|
+
|
|
14
|
+
- authorization management
|
|
15
|
+
auth users, roles, role assignments, permission rules, and permission evaluation
|
|
16
|
+
|
|
17
|
+
## Account Endpoints
|
|
18
|
+
|
|
19
|
+
Registered through:
|
|
20
|
+
|
|
21
|
+
```csharp
|
|
22
|
+
builder.Services.AddChillAuthIdentityApi<AppDbContext, IdentityUser>();
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Typical routes:
|
|
26
|
+
|
|
27
|
+
- `/api/chill-auth/account/register`
|
|
28
|
+
- `/api/chill-auth/account/login`
|
|
29
|
+
- `/api/chill-auth/account/refresh`
|
|
30
|
+
- `/api/chill-auth/account/change-password`
|
|
31
|
+
- `/api/chill-auth/account/request-password-reset`
|
|
32
|
+
- `/api/chill-auth/account/reset-password`
|
|
33
|
+
|
|
34
|
+
These are the routes used internally by `ChillSharpClient`.
|
|
35
|
+
|
|
36
|
+
`RegisterAuthIdentityRequest` also supports:
|
|
37
|
+
|
|
38
|
+
- `DisplayName`
|
|
39
|
+
- `DisplayCultureName`
|
|
40
|
+
- `CreateChillAuthUser`
|
|
41
|
+
|
|
42
|
+
When `CreateChillAuthUser` is enabled and `DisplayCultureName` is provided, the linked `AuthUser` is automatically preset with:
|
|
43
|
+
|
|
44
|
+
- `DisplayCultureName`
|
|
45
|
+
- `DisplayTimeZone`
|
|
46
|
+
- `DisplayDateFormat`
|
|
47
|
+
- `DisplayNumberFormat`
|
|
48
|
+
|
|
49
|
+
The server resolves those defaults from the selected culture by using a best-effort time-zone mapping plus the culture date and number separators.
|
|
50
|
+
|
|
51
|
+
## Authorization Management Endpoints
|
|
52
|
+
|
|
53
|
+
Registered through:
|
|
54
|
+
|
|
55
|
+
```csharp
|
|
56
|
+
builder.Services.AddChillAuthApi<AppDbContext>();
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Typical route groups:
|
|
60
|
+
|
|
61
|
+
- `/api/chill-auth/users`
|
|
62
|
+
- `/api/chill-auth/roles`
|
|
63
|
+
- `/api/chill-auth/permissions`
|
|
64
|
+
|
|
65
|
+
These endpoints manage:
|
|
66
|
+
|
|
67
|
+
- `AuthUser`
|
|
68
|
+
- `AuthRole`
|
|
69
|
+
- `AuthUserRole`
|
|
70
|
+
- `AuthPermissionRule`
|
|
71
|
+
- permission evaluation results
|
|
72
|
+
|
|
73
|
+
`AuthUser` now also carries optional UI display preferences:
|
|
74
|
+
|
|
75
|
+
- `DisplayCultureName`
|
|
76
|
+
- `DisplayTimeZone`
|
|
77
|
+
- `DisplayDateFormat`
|
|
78
|
+
- `DisplayNumberFormat`
|
|
79
|
+
|
|
80
|
+
`AuthUser` and `AuthRole` also carry:
|
|
81
|
+
|
|
82
|
+
- `MenuHierarchy`
|
|
83
|
+
|
|
84
|
+
`MenuHierarchy` is used by the schema menu endpoints to filter which menu nodes are visible to the current user.
|
|
85
|
+
|
|
86
|
+
- values can be single codes or comma-separated lists
|
|
87
|
+
- user and active role values are merged before filtering
|
|
88
|
+
- `*` means full menu access
|
|
89
|
+
- any other value works as a prefix match, for example `SECTION-A` allows nodes whose menu hierarchy starts with `SECTION-A`
|
|
90
|
+
- an empty merged menu hierarchy set means no menu access
|
|
91
|
+
|
|
92
|
+
For the full menu-tree model and endpoint behavior, see [MenuGuide/README.md](../MenuGuide/README.md).
|
|
93
|
+
|
|
94
|
+
## Token Lifetimes
|
|
95
|
+
|
|
96
|
+
ChillSharp auth account endpoints issue protected bearer access tokens and refresh tokens. These access tokens are not JWTs, but they are used in the same `Authorization: Bearer ...` header shape.
|
|
97
|
+
|
|
98
|
+
Default lifetimes:
|
|
99
|
+
|
|
100
|
+
- access token: 20 minutes
|
|
101
|
+
- refresh token: 14 days
|
|
102
|
+
|
|
103
|
+
Built-in environment variables:
|
|
104
|
+
|
|
105
|
+
- `CHILLSHARP_AUTH_ACCESS_TOKEN_MINUTES`
|
|
106
|
+
Positive integer number of minutes before an access token expires.
|
|
107
|
+
- `CHILLSHARP_AUTH_REFRESH_TOKEN_DAYS`
|
|
108
|
+
Positive integer number of days before a refresh token expires.
|
|
109
|
+
|
|
110
|
+
These variables are read by `ChillAuthIdentityApiOptions` and `ChillIdentityApiOptions` when the options object is created. Explicit code configuration still wins:
|
|
111
|
+
|
|
112
|
+
```csharp
|
|
113
|
+
builder.Services.AddChillAuthIdentityApi<AppDbContext, IdentityUser>(options =>
|
|
114
|
+
{
|
|
115
|
+
options.AccessTokenLifetime = TimeSpan.FromMinutes(30);
|
|
116
|
+
options.RefreshTokenLifetime = TimeSpan.FromDays(7);
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Context Requirements
|
|
121
|
+
|
|
122
|
+
The host context must:
|
|
123
|
+
|
|
124
|
+
- implement `IChillAuthDbContext`
|
|
125
|
+
- include `modelBuilder.AddChillAuthModel()`
|
|
126
|
+
|
|
127
|
+
For Identity-backed accounts, the context must also be a valid EF store for ASP.NET Core Identity, typically:
|
|
128
|
+
|
|
129
|
+
```csharp
|
|
130
|
+
public class AppDbContext : IdentityDbContext<IdentityUser>, IChillContext, IChillAuthDbContext
|
|
131
|
+
{
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Root User Bootstrap
|
|
136
|
+
|
|
137
|
+
`AddChillAuthIdentityApi(...)` can bootstrap a root account on startup.
|
|
138
|
+
|
|
139
|
+
Supported configuration:
|
|
140
|
+
|
|
141
|
+
- direct options in code
|
|
142
|
+
- environment variables
|
|
143
|
+
|
|
144
|
+
Default environment variables:
|
|
145
|
+
|
|
146
|
+
- `CHILLSHARP_AUTH_ROOT_USERNAME`
|
|
147
|
+
- `CHILLSHARP_AUTH_ROOT_PASSWORD`
|
|
148
|
+
- `CHILLSHARP_AUTH_ROOT_EMAIL`
|
|
149
|
+
- `CHILLSHARP_AUTH_ROOT_DISPLAY_NAME`
|
|
150
|
+
|
|
151
|
+
When enabled, the bootstrap flow can also create the linked ChillSharp `AuthUser` with permission-management access.
|
|
152
|
+
|
|
153
|
+
## Permission Management Access
|
|
154
|
+
|
|
155
|
+
Being authenticated is not enough to manage the auth module.
|
|
156
|
+
|
|
157
|
+
Auth-management endpoints require a ChillSharp auth user with permission-management rights, typically:
|
|
158
|
+
|
|
159
|
+
- `CanManagePermissions = true`
|
|
160
|
+
|
|
161
|
+
This is the critical bootstrap problem for a clean database:
|
|
162
|
+
|
|
163
|
+
- the first registered Identity user may exist
|
|
164
|
+
- the linked `AuthUser` may exist
|
|
165
|
+
- but no one may yet have rights to manage roles and permissions
|
|
166
|
+
|
|
167
|
+
That is why root-user bootstrap or another trusted setup path matters.
|
|
168
|
+
|
|
169
|
+
## Client Usage
|
|
170
|
+
|
|
171
|
+
Use the normal Chill base URL:
|
|
172
|
+
|
|
173
|
+
```csharp
|
|
174
|
+
var client = new ChillSharpClient("http://localhost:5000/api/chill");
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
`ChillSharpClient` automatically switches to `/api/chill-auth/...` for auth methods.
|
|
178
|
+
|
|
179
|
+
Examples:
|
|
180
|
+
|
|
181
|
+
- `RegisterAuthAccount`
|
|
182
|
+
- `LoginAuthAccount`
|
|
183
|
+
- `RefreshAuthAccount`
|
|
184
|
+
- `ChangeAuthPassword`
|
|
185
|
+
- `CreateAuthRole`
|
|
186
|
+
- `CreateAuthPermissionRule`
|
|
187
|
+
- `EvaluateAuthEntityPermission`
|
|
188
|
+
|
|
189
|
+
User list and user detail payloads also expose:
|
|
190
|
+
|
|
191
|
+
- `DisplayCultureName`
|
|
192
|
+
- `DisplayTimeZone`
|
|
193
|
+
- `DisplayDateFormat`
|
|
194
|
+
- `DisplayNumberFormat`
|
|
195
|
+
|
|
196
|
+
## Token Handling
|
|
197
|
+
|
|
198
|
+
`ChillSharpClient` stores:
|
|
199
|
+
|
|
200
|
+
- access token
|
|
201
|
+
- refresh token
|
|
202
|
+
|
|
203
|
+
If a refresh token is present, the client can renew the access token automatically during later authenticated calls.
|
|
204
|
+
|
|
205
|
+
## Relationship With The Permission Model
|
|
206
|
+
|
|
207
|
+
The exact permission-resolution rules are documented separately in:
|
|
208
|
+
|
|
209
|
+
- [PermissionModel/README.md](../PermissionModel/README.md)
|
|
210
|
+
|
|
211
|
+
Use that document for the precedence and scope model. Use this one for registration and runtime auth flow.
|
|
212
|
+
|
|
213
|
+
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
Versione italiana: [Italiano](../it/AuthenticationModel/how-to-integreate-auth-minimal-api.md)
|
|
2
|
+
|
|
3
|
+
Sure. Here’s the updated, correct, modern version of the setup using **Microsoft.IdentityModel.JsonWebTokens**, because Microsoft decided the old JWT library needed to be “legacy” for fun.
|
|
4
|
+
|
|
5
|
+
This is the clean way to do:
|
|
6
|
+
|
|
7
|
+
✅ Identity user store
|
|
8
|
+
✅ Minimal API login/register
|
|
9
|
+
✅ JWT Bearer tokens
|
|
10
|
+
✅ No cookies
|
|
11
|
+
✅ No UI
|
|
12
|
+
✅ No outdated JwtSecurityTokenHandler
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# ✅ ASP.NET Core Minimal Identity API + JWT (Modern JsonWebTokenHandler)
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
# ✅ 1. Install Packages
|
|
21
|
+
|
|
22
|
+
Run:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
|
|
26
|
+
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
|
|
27
|
+
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
|
|
28
|
+
dotnet add package Microsoft.IdentityModel.JsonWebTokens
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
No `System.IdentityModel.Tokens.Jwt`. We are enlightened now.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
# ✅ 2. Create Identity DbContext
|
|
36
|
+
|
|
37
|
+
```csharp
|
|
38
|
+
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
|
39
|
+
using Microsoft.EntityFrameworkCore;
|
|
40
|
+
|
|
41
|
+
public class AppDbContext : IdentityDbContext
|
|
42
|
+
{
|
|
43
|
+
public AppDbContext(DbContextOptions<AppDbContext> options)
|
|
44
|
+
: base(options) { }
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
# ✅ 3. Configure Database + IdentityCore
|
|
51
|
+
|
|
52
|
+
In `Program.cs`:
|
|
53
|
+
|
|
54
|
+
```csharp
|
|
55
|
+
builder.Services.AddDbContext<AppDbContext>(options =>
|
|
56
|
+
options.UseSqlServer(builder.Configuration.GetConnectionString("Default")));
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Now add Identity:
|
|
60
|
+
|
|
61
|
+
```csharp
|
|
62
|
+
builder.Services.AddIdentityCore<IdentityUser>()
|
|
63
|
+
.AddEntityFrameworkStores<AppDbContext>()
|
|
64
|
+
.AddDefaultTokenProviders();
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
✅ No UI
|
|
68
|
+
✅ No Razor
|
|
69
|
+
✅ No cookie circus
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
# ✅ 4. Configure JWT Authentication (Bearer)
|
|
74
|
+
|
|
75
|
+
Add imports:
|
|
76
|
+
|
|
77
|
+
```csharp
|
|
78
|
+
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|
79
|
+
using Microsoft.IdentityModel.Tokens;
|
|
80
|
+
using System.Text;
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Then:
|
|
84
|
+
|
|
85
|
+
```csharp
|
|
86
|
+
var jwtKey = builder.Configuration["Jwt:Key"]!;
|
|
87
|
+
var jwtIssuer = builder.Configuration["Jwt:Issuer"]!;
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Now configure:
|
|
91
|
+
|
|
92
|
+
```csharp
|
|
93
|
+
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
|
94
|
+
.AddJwtBearer(options =>
|
|
95
|
+
{
|
|
96
|
+
options.TokenValidationParameters = new TokenValidationParameters
|
|
97
|
+
{
|
|
98
|
+
ValidateIssuer = true,
|
|
99
|
+
ValidIssuer = jwtIssuer,
|
|
100
|
+
|
|
101
|
+
ValidateAudience = false,
|
|
102
|
+
|
|
103
|
+
ValidateIssuerSigningKey = true,
|
|
104
|
+
IssuerSigningKey = new SymmetricSecurityKey(
|
|
105
|
+
Encoding.UTF8.GetBytes(jwtKey)),
|
|
106
|
+
|
|
107
|
+
ValidateLifetime = true
|
|
108
|
+
};
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
# ✅ 5. Enable Authorization
|
|
115
|
+
|
|
116
|
+
```csharp
|
|
117
|
+
builder.Services.AddAuthorization();
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
# ✅ 6. Add Middleware
|
|
123
|
+
|
|
124
|
+
After `var app = builder.Build();`
|
|
125
|
+
|
|
126
|
+
```csharp
|
|
127
|
+
app.UseAuthentication();
|
|
128
|
+
app.UseAuthorization();
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
If you skip this, nothing works and you’ll blame yourself, incorrectly.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
# ✅ 7. Generate JWT Token (Modern JsonWebTokenHandler)
|
|
136
|
+
|
|
137
|
+
Add imports:
|
|
138
|
+
|
|
139
|
+
```csharp
|
|
140
|
+
using Microsoft.IdentityModel.JsonWebTokens;
|
|
141
|
+
using System.Security.Claims;
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Now define:
|
|
145
|
+
|
|
146
|
+
```csharp
|
|
147
|
+
string GenerateJwtToken(IdentityUser user)
|
|
148
|
+
{
|
|
149
|
+
var claims = new List<Claim>
|
|
150
|
+
{
|
|
151
|
+
new Claim(JwtRegisteredClaimNames.Sub, user.Id),
|
|
152
|
+
new Claim(JwtRegisteredClaimNames.Email, user.Email!)
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
var key = new SymmetricSecurityKey(
|
|
156
|
+
Encoding.UTF8.GetBytes(jwtKey));
|
|
157
|
+
|
|
158
|
+
var creds = new SigningCredentials(
|
|
159
|
+
key,
|
|
160
|
+
SecurityAlgorithms.HmacSha256);
|
|
161
|
+
|
|
162
|
+
var tokenDescriptor = new SecurityTokenDescriptor
|
|
163
|
+
{
|
|
164
|
+
Subject = new ClaimsIdentity(claims),
|
|
165
|
+
Expires = DateTime.UtcNow.AddHours(2),
|
|
166
|
+
Issuer = jwtIssuer,
|
|
167
|
+
SigningCredentials = creds
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
var handler = new JsonWebTokenHandler();
|
|
171
|
+
|
|
172
|
+
return handler.CreateToken(tokenDescriptor);
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
✅ This is the replacement for the old JwtSecurityTokenHandler.
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
# ✅ 8. Register Endpoint (Minimal API)
|
|
181
|
+
|
|
182
|
+
```csharp
|
|
183
|
+
app.MapPost("/register", async (
|
|
184
|
+
UserManager<IdentityUser> userManager,
|
|
185
|
+
RegisterRequest request) =>
|
|
186
|
+
{
|
|
187
|
+
var user = new IdentityUser
|
|
188
|
+
{
|
|
189
|
+
UserName = request.Email,
|
|
190
|
+
Email = request.Email
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
var result = await userManager.CreateAsync(user, request.Password);
|
|
194
|
+
|
|
195
|
+
if (!result.Succeeded)
|
|
196
|
+
return Results.BadRequest(result.Errors);
|
|
197
|
+
|
|
198
|
+
return Results.Ok("User registered");
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
# ✅ 9. Login Endpoint (Returns JWT)
|
|
205
|
+
|
|
206
|
+
```csharp
|
|
207
|
+
app.MapPost("/login", async (
|
|
208
|
+
UserManager<IdentityUser> userManager,
|
|
209
|
+
LoginRequest request) =>
|
|
210
|
+
{
|
|
211
|
+
var user = await userManager.FindByEmailAsync(request.Email);
|
|
212
|
+
|
|
213
|
+
if (user == null)
|
|
214
|
+
return Results.Unauthorized();
|
|
215
|
+
|
|
216
|
+
var valid = await userManager.CheckPasswordAsync(user, request.Password);
|
|
217
|
+
|
|
218
|
+
if (!valid)
|
|
219
|
+
return Results.Unauthorized();
|
|
220
|
+
|
|
221
|
+
var token = GenerateJwtToken(user);
|
|
222
|
+
|
|
223
|
+
return Results.Ok(new { token });
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
# ✅ 10. Protect an Endpoint
|
|
230
|
+
|
|
231
|
+
```csharp
|
|
232
|
+
app.MapGet("/me", (ClaimsPrincipal user) =>
|
|
233
|
+
{
|
|
234
|
+
var email = user.FindFirst(ClaimTypes.Email)?.Value;
|
|
235
|
+
|
|
236
|
+
return Results.Ok(new { email });
|
|
237
|
+
})
|
|
238
|
+
.RequireAuthorization();
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
# ✅ 11. Add Request Models
|
|
244
|
+
|
|
245
|
+
```csharp
|
|
246
|
+
public record RegisterRequest(string Email, string Password);
|
|
247
|
+
|
|
248
|
+
public record LoginRequest(string Email, string Password);
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
# ✅ 12. Configure appsettings.json
|
|
254
|
+
|
|
255
|
+
```json
|
|
256
|
+
"Jwt": {
|
|
257
|
+
"Key": "REPLACE_WITH_A_REAL_SECRET_32+_CHARS",
|
|
258
|
+
"Issuer": "MyApiAuthServer"
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Make the key long and random, unless you want attackers logging in as you for sport.
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
# ✅ Result
|
|
267
|
+
|
|
268
|
+
Now you have:
|
|
269
|
+
|
|
270
|
+
✅ `/register`
|
|
271
|
+
✅ `/login` → returns JWT
|
|
272
|
+
✅ Protected endpoints with Bearer token
|
|
273
|
+
✅ Identity user store in SQL
|
|
274
|
+
✅ No cookies
|
|
275
|
+
✅ No UI
|
|
276
|
+
✅ No legacy JWT handler
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
# If You Want Next Steps
|
|
281
|
+
|
|
282
|
+
The moment you want:
|
|
283
|
+
|
|
284
|
+
* Refresh tokens
|
|
285
|
+
* Roles + claims
|
|
286
|
+
* Password reset endpoints
|
|
287
|
+
* Email confirmation
|
|
288
|
+
* `/logout` with JWT invalidation (annoying)
|
|
289
|
+
|
|
290
|
+
Then authentication becomes a *real* system, not a demo.
|
|
291
|
+
|
|
292
|
+
Still, this setup is the clean foundation Microsoft should’ve shipped by default.
|
|
293
|
+
|