Atterrissage après connexion
Après la connexion, différents utilisateurs devraient atterrir sur différentes pages — un administrateur sur l'accueil d'administration, un client sur son enregistrement (ou un sélecteur lorsqu'il en a plusieurs). Sovrium exprime cela comme une configuration d'authentification, et non comme une logique de redirection par page : chaque rôle déclare un defaultLanding, le bloc auth déclare un point de montage landingPath, et noAccessPath gère le cas non concordant.
auth:
strategies:
- type: emailAndPassword
scopeTables: [clients]
defaultRole: customer-admin
landingPath: /portal
noAccessPath: /403
roles:
- name: engineer
defaultLanding: /admin
- name: customer-admin
defaultLanding: /portal/clients/$currentUser.assignments.clients[0]
pickerLanding: /portal/select/clients
Champs de configuration
Deux champs sur auth, deux sur chaque rôle :
| Champ | Niveau | Description |
|---|---|---|
landingPath |
auth |
Chemin de montage du résolveur de moteur. Les sessions qui naviguent ici sont redirigées vers le defaultLanding du rôle correspondant. Doit commencer par /. Obligatoire dès qu'un rôle définit defaultLanding ou pickerLanding. |
noAccessPath |
auth |
Chemin de repli lorsqu'aucun defaultLanding de rôle ne correspond à la session. Doit commencer par /. Par défaut /403. |
defaultLanding |
roles[] |
URL d'atterrissage par rôle. Doit commencer par /. Peut contenir au plus un jeton $currentUser.assignments.<table>[0]. |
pickerLanding |
roles[] |
Repli multi-enregistrements pour un defaultLanding à modèle. Doit commencer par /. Ne doit pas contenir de jeton d'affectation. |
landingPath est contrôlé par l'utilisateur — choisissez /portal, /dashboard, /home, ou n'importe quoi d'autre. Il n'y a pas de convention de moteur. Il en va de même pour pickerLanding : /portal/select/clients, /companies-picker, comme bon vous semble.
Logique de résolution
Lorsqu'une session authentifiée navigue vers auth.landingPath, le moteur parcourt auth.roles[] dans l'ordre de déclaration et applique le premier rôle que l'utilisateur détient. Pour le defaultLanding de ce rôle :
Forme de defaultLanding |
Nombre d'affectations pour la <table> à modèle |
Action du moteur |
|---|---|---|
| URL simple (sans jeton) | s.o. | Rediriger vers defaultLanding sans condition. |
| À modèle (un jeton) | Exactement une affectation | Substituer l'ID d'affectation, rediriger là. |
| À modèle (un jeton) | Plus d'une affectation | Rediriger vers le pickerLanding du rôle. |
| Aucun rôle concordant / aucune affectation | s.o. | Rediriger vers noAccessPath (par défaut /403). |
Interpolation $currentUser.assignments
Le jeton $currentUser.assignments.<table> se résout en l'ensemble des ID d'enregistrement issus des lignes user_access de l'utilisateur pour <table> (une table de périmètre). Il apparaît de deux manières distinctes :
Dans une URL defaultLanding — la forme à enregistrement unique $currentUser.assignments.<table>[0] substitue le premier ID d'affectation, produisant un lien direct vers cet enregistrement :
roles:
- name: customer-admin
defaultLanding: /portal/clients/$currentUser.assignments.clients[0]
pickerLanding: /portal/select/clients
Un rôle peut contenir au plus un tel jeton (le résolveur ne peut pas déduire quel périmètre compter avec deux). Un pickerLanding ne doit en contenir aucun — par définition, le cas multi-enregistrements n'a pas d'ID unique à substituer.
Dans un dataSource.filter — la forme non indexée $currentUser.assignments.<table> se résout en la liste complète des ID, de sorte que la page de sélection liste exactement les enregistrements que l'utilisateur peut atteindre :
pages:
- name: client-picker
path: /portal/select/clients
access: authenticated
components:
- type: list
props: { id: clients }
dataSource:
table: clients
filter:
- field: id
operator: in
value: $currentUser.assignments.clients
children:
- type: text
content: $record.name
La page landingPath est le garde d'accès
landingPath doit être adossé à une page co-localisée déclarée au même path. Cette page est le garde d'accès non authentifié : son bloc access renvoie les visiteurs anonymes vers /login avant que le résolveur d'atterrissage ne s'exécute. Pour les visiteurs authentifiés, le résolveur redirige avant que cette page (généralement vide) ne soit rendue.
auth:
landingPath: /portal
# ...
pages:
- name: portal-landing
path: /portal
access:
require: authenticated
redirectTo: /login
components: [] # never rendered for authed users — resolver redirects first
Oublier la page de garde co-localisée est l'erreur la plus courante : landingPath: /portal sans page /portal laisse les visiteurs anonymes sans protection. Associez toujours le chemin de montage à une page qui exige l'authentification.
Exemple complet
auth:
strategies:
- type: emailAndPassword
scopeTables: [clients]
defaultRole: customer-admin
landingPath: /portal
noAccessPath: /403
roles:
- name: engineer
defaultLanding: /admin
- name: customer-admin
defaultLanding: /portal/clients/$currentUser.assignments.clients[0]
pickerLanding: /portal/select/clients
pages:
- name: portal-landing
path: /portal
access: { require: authenticated, redirectTo: /login }
components: []
- name: client-detail
path: /portal/clients/:id
access: authenticated
components: []
- name: client-picker
path: /portal/select/clients
access: authenticated
components: []
- name: admin-home
path: /admin
access: [engineer]
components: []
- name: forbidden
path: /403
access: authenticated
components: []
Dans cette application : un engineer atterrit sur /admin ; un customer-admin avec un seul client atterrit sur la page de détail de ce client ; avec plusieurs, sur le sélecteur ; et quiconque que le résolveur ne peut pas placer atteint /403.
Pages associées
- Rôles & RBAC — là où
defaultLanding/pickerLandingsont définis sur les rôles. - Sessions —
scopeTables,user_accesset$currentUser.activeAssignment. - Pages —
path,accessetdataSource.filterde page.