2 votes

Déconnexion des clients uniquement dans IdentityServer4

Existe-t-il un moyen d'exécuter une signature unique ? pour les clients uniquement en utilisant IdentityServer4 ? Je n'ai aucun problème à exécuter le single-sign-out pour les clients et IdentityServer en utilisant l'option endsession point final. Ce que j'aimerais faire, cependant, c'est fournir un moyen de forcer tous les clients à s'authentifier à nouveau lors de la prochaine demande (pour obtenir de nouvelles réclamations) mais sans forcer l'utilisateur à saisir à nouveau ses informations d'identification.

Le cas d'utilisation consiste pour l'utilisateur à modifier les informations de son profil qui sont stockées dans les réclamations. Par exemple, son nom. Lorsque l'utilisateur modifie ces informations, tous les autres clients doivent être informés que les créances qu'ils détiennent actuellement ne sont plus valables. Pour ce faire, l'utilisateur peut se déconnecter complètement, mais il doit alors saisir à nouveau son identifiant et son mot de passe.

En regardant le flux, je suppose que ce que j'essaie de faire est d'exécuter la fonction interne EndSessionCallbackEndpoint directement, sans supprimer le cookie d'authentification de l'IdentityServer lui-même.

2voto

Dave Mateer Points 8717

Voici une solution qui fonctionne, mais j'ai vraiment l'impression d'abuser du système. Si quelqu'un a une méthode "standard" pour fournir la fonctionnalité attendue, merci de me le faire savoir.

Cette solution modifie la Logout pour "sentir" la présence d'un PostLogoutRedirectUri et d'ignorer la suppression du cookie d'authentification local. Il est évident que cette solution n'est pas particulièrement évolutive ou élégante.

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logout(LogoutInputModel model)
{
    // build a model so the logged out page knows what to display
    var vm = await BuildLoggedOutViewModelAsync(model.LogoutId);

    // Special post-logout URL that should only log out clients, but keep the local authentication cookie.
    bool clientsOnly = !string.IsNullOrEmpty(vm.PostLogoutRedirectUri) && vm.PostLogoutRedirectUri.StartsWith("https://example.com/EditProfile");

    if (User?.Identity.IsAuthenticated == true && !clientsOnly)
    {
        // delete local authentication cookie
        await _signInManager.SignOutAsync();

        // raise the logout event
        await _events.RaiseAsync(new UserLogoutSuccessEvent(User.GetSubjectId(), User.GetDisplayName()));
    }

    // check if we need to trigger sign-out at an upstream identity provider
    if (vm.TriggerExternalSignout)
    {
        // build a return URL so the upstream provider will redirect back to us after the
        // user has logged out. this allows us to then complete our single sign-out processing.
        string url = Url.Action("Logout", new { logoutId = vm.LogoutId });

        // this triggers a redirect to the external provider for sign-out
        return SignOut(new AuthenticationProperties { RedirectUri = url }, vm.ExternalAuthenticationScheme);
    }

    return View("LoggedOut", vm);
}

1voto

mackie Points 326

Il s'agit d'une procédure assez simple, exposée par le biais d'API publiques ( IIdentityServerInteractionService ) dans l'IDS4. Il s'agit d'un exemple très simplifié des étapes à suivre. Il couvre à la fois le signout du canal de départ et le signout du canal d'arrivée, car les deux sont déclenchés par la demande adressée à la fonction SignOutIFrameUrl .

Nous devons d'abord créer un contexte de déconnexion et rediriger vers une action qui effectuera la déconnexion :

var signoutId = await _identityInteractionService.CreateLogoutContextAsync();
return RedirectToAction(nameof(ClientSignout), new { signoutId });

Action ClientSignout :

var context = await _identityInteractionService.GetLogoutContextAsync(signoutId);
ViewBag.SignOutIframeUrl = context.SignOutIFrameUrl;
return View();

ClientSignout.cshtml :

<iframe src="@ViewBag.SignOutIframeUrl" id="SignOutIframe" frameborder="0" scrolling="no" style="display:none" />
//TODO: Detect client-side once iframe has loaded and then maybe redirect somewhere else?

Le code ici ne touche pas du tout à la session d'authentification en cours, mais une autre solution consisterait à forcer un rafraîchissement de l'ID de session en cours et donc à déclencher un rafraîchissement dans tous les clients ayant mis en place un suivi de session.

ETA : plus j'y pense, plus je pense que l'approche du contrôle de session côté client est la bonne. Le client a le contrôle sur ce qu'il doit faire ensuite. Une autre option est que le client fasse des appels périodiques au point de terminaison userinfo pour obtenir des réclamations mises à jour en utilisant le jeton d'accès fourni. En fait, nous utilisons les trois mécanismes à bon escient.

Octobre 2020 : En outre, je pense que, de nos jours, je préférerais utiliser la spécification de la voie de retour de l'OIDC : https://openid.net/specs/openid-connect-backchannel-1_0.html

J'ai récemment réalisé un PoC dans lequel un code de backend peut mettre fin à des sessions client pour un ensemble donné d'utilisateurs et de clients sans impliquer le navigateur de l'utilisateur. C'est très utile si l'on veut forcer la réauthentification en raison de changements de politique ou d'une fonction "sign me out everywhere" dans l'IDP.

Il convient toutefois de noter que la norme identityserver4 Le code doit être modifié pour que cela fonctionne, car il est actuellement supposé qu'il ne sera utilisé que dans le cadre du processus normal de signature.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X