IdentityModel / oidc-client-js

OpenID Connect (OIDC) and OAuth2 protocol support for browser-based JavaScript applications
Apache License 2.0
2.43k stars 840 forks source link

How to achieve single sign-out in SSO (multiple forms of clients: mvc and js) #1283

Closed greenlgy closed 3 years ago

greenlgy commented 3 years ago

note

I have three applications, namely :

I have implemented single sign-on

Issues

When I log out from the javascript client, the ASP.net MVC client does not log out, and it still runs normally Similarly, when I log out from the ASP.net MVC client, the javascript client also does not log out and still works normally.

My purpose is to achieve single sign-out. The following is my code, I don't know what is wrong, I hope to give me some help and suggestions.

Code

[HttpGet] public async Task Logout(string logoutId) { // build a model so the logout page knows what to display var vm = await BuildLogoutViewModelAsync(logoutId);

if (vm.ShowLogoutPrompt == false)
{
    // if the request for logout was properly authenticated from IdentityServer, then
    // we don't need to show the prompt and can just log the user out directly.
    return await Logout(vm);
}

return View(vm);

}

///

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

if (User?.Identity.IsAuthenticated == true)
{
    // 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);

}

private async Task BuildLogoutViewModelAsync(string logoutId) { var vm = new LogoutViewModel { LogoutId = logoutId, ShowLogoutPrompt = AccountOptions.ShowLogoutPrompt };

if (User?.Identity.IsAuthenticated != true)
{
    // if the user is not authenticated, then just show logged out page
    vm.ShowLogoutPrompt = false;
    return vm;
}

var context = await _interaction.GetLogoutContextAsync(logoutId);
if (context?.ShowSignoutPrompt == false)
{
    // it's safe to automatically sign-out
    vm.ShowLogoutPrompt = false;
    return vm;
}

// show the logout prompt. this prevents attacks where the user
// is automatically signed out by another malicious web page.
return vm;

}

private async Task BuildLoggedOutViewModelAsync(string logoutId) { // get context information (client name, post logout redirect URI and iframe for federated signout) var logout = await _interaction.GetLogoutContextAsync(logoutId);

var vm = new LoggedOutViewModel
{
    AutomaticRedirectAfterSignOut = AccountOptions.AutomaticRedirectAfterSignOut,
    PostLogoutRedirectUri = logout?.PostLogoutRedirectUri,
    ClientName = string.IsNullOrEmpty(logout?.ClientName) ? logout?.ClientId : logout?.ClientName,
    SignOutIframeUrl = logout?.SignOutIFrameUrl,
    LogoutId = logoutId
};

if (User?.Identity.IsAuthenticated == true)
{
    var idp = User.FindFirst(JwtClaimTypes.IdentityProvider)?.Value;
    if (idp != null && idp != IdentityServer4.IdentityServerConstants.LocalIdentityProvider)
    {
        var providerSupportsSignout = await HttpContext.GetSchemeSupportsSignOutAsync(idp);
        if (providerSupportsSignout)
        {
            if (vm.LogoutId == null)
            {
                // if there's no current logout context, we need to create one
                // this captures necessary info from the current logged in user
                // before we signout and redirect away to the external IdP for signout
                vm.LogoutId = await _interaction.CreateLogoutContextAsync();
            }

            vm.ExternalAuthenticationScheme = idp;
        }
    }
}

return vm;

}

brockallen commented 3 years ago

https://docs.duendesoftware.com/identityserver/v5/ui/logout/notification/#browser-based-javascript-clients