为了账号安全,请及时绑定邮箱和手机立即绑定

为什么最终用户必须注销两次?

为什么最终用户必须注销两次?

C#
心有法竹 2021-11-21 15:15:58
我试图让 IdentityServer4 在新的 .NET Core 2.1 应用程序中工作(它在 .NET Core 2.0 应用程序中完美运行)。我尝试了以下方法:1)下载这个项目,即IdentityServer4应用:https : //github.com/ghstahl/IdentityServer4-Asp.Net-2.1-Identity-Examples/tree/e0aeeff7e078aa082c8e16029dd2c220acc77d7b2)下载这个项目,它是使用Identity Server4应用的MVC应用:https : //github.com/IdentityServer/IdentityServer4.Samples/tree/dev/Quickstarts/6_AspNetIdentity/src/MvcClient。3) 将两个项目添加到同一个解决方案中。MVC项目使用IdentityServer项目进行认证;授权等我必须进行以下更改:1) 更改 IdentityServer 应用程序中包含的 Startup(AddIdentityServer 现在接受一个参数):services.AddIdentityServer(options =>{    options.UserInteraction.LoginUrl = "/Identity/Account/Login";    options.UserInteraction.LogoutUrl = "/Identity/Account/Logout";})2) 将 IdentityServer 应用程序配置为侦听端口 5000 并在身份服务器上禁用 SSL。除了注销功能外,一切都按预期开箱即用。当我在 MVC 应用程序中单击注销时;在 MVC 应用程序中调用以下代码:public async Task Logout() {     await HttpContext.SignOutAsync("Cookies");     await HttpContext.SignOutAsync("oidc"); } 然后将用户重定向到 IdentityServer 应用程序中的 Logout.cshtml。但是,他们必须再次单击注销(在 IdentityServer 应用程序上)才能实际注销,即他们在 MVC 应用程序中单击注销(第二点),然后在 IdentityServer 中注销(第一点)。为什么最终用户必须注销两次?
查看完整描述

3 回答

?
喵喔喔

TA贡献1735条经验 获得超5个赞

在位于脚手架 ASP.NET Core Identity 代码Account/Logout下的页面中,Areas/Identity/Account/Logout.cshtml.cs有一个如下所示的OnGet处理程序:


public void OnGet() { }

因为这是使用 ASP.NET Core Razor Pages,所以所做的只是呈现相应的Logout.cshtml页面。在您的示例中,当您点击LogoutMVC 应用程序时,它会清除自己的 cookie,然后将您传递给 IS4 应用程序(OnGet特别是 )。因为这个OnGet处理程序是空的,所以它实际上并没有做任何事情,而且肯定不会让您退出 IS4 应用程序。


如果您查看OnPost内部的处理程序Logout.cshtml.cs,您会看到它看起来像这样:


public async Task<IActionResult> OnPost(string returnUrl = null)

{

    await _signInManager.SignOutAsync();

    // ...

}

这个调用SignOutAsync完全符合它的建议:它使您退出 IS4 本身。但是,在您当前的工作流程中,OnPost不会调用此处理程序。该OnGet处理器被间接调用当您使用Logout的MVC应用程序,因为我已经提到过。


现在,如果您查看Quickstart.UI项目中 IS4 注销的控制器/操作实现,您会发现它本质上是将GET请求传递给POST请求。这是代码,删除了注释:


[HttpGet]

public async Task<IActionResult> Logout(string logoutId)

{

    var vm = await BuildLogoutViewModelAsync(logoutId);


    if (vm.ShowLogoutPrompt == false)

        return await Logout(vm);


    return View(vm);

}

注销时,有一个设置可控制是否应首先提示用户确认是否要注销。这主要是这段代码所处理的 -POST如果不需要提示,它会直接将其传递给请求处理程序。这是 的代码片段POST:


[HttpPost]

[ValidateAntiForgeryToken]

public async Task<IActionResult> Logout(LogoutInputModel model)

{

    var vm = await BuildLoggedOutViewModelAsync(model.LogoutId);


    if (User?.Identity.IsAuthenticated == true)

    {

        await HttpContext.SignOutAsync();


        // ...

    }


    // ...


    return View("LoggedOut", vm);

}

这里重要的一行是调用HttpContext.SignOutAsync- 这最终会删除 IS4 用来让您保持登录状态的 cookie。一旦它被删除,您就会退出 IS4。最终,这是您当前实现中所缺少的。


在最简单的层面上,您可以通过将您的问题更新OnGet为如下所示来解决您的问题:


public async Task<IActionResult> OnGet()

{

    if (User?.Identity.IsAuthenticated == true)

    {

        await _signInManager.SignOutAsync();          

        return RedirectToPage(); // A redirect ensures that the cookies has gone.

    }


    return Page();

}

这不支持ShowLogoutPrompt我上面详述的选项,只是为了让这个答案更短一些。除此之外,_signInManager鉴于您在 ASP.NET Core Identity 世界中,它仅用于注销。


我鼓励你去探索从完整的源代码Quickstart.UI执行情况,以便支持ShowLogoutPrompt,returnUrl等等-我不可能做到这一点这里没有写一本书。


查看完整回答
反对 回复 2021-11-21
?
www说

TA贡献1775条经验 获得超8个赞

简单的注销功能是可能的,如下所示:


        private readonly SignInManager<IdentityUser> _signInManager;

        private readonly ILogger<LogoutModel> _logger;

        private readonly IIdentityServerInteractionService _interaction;

        public LogoutModel(SignInManager<IdentityUser> signInManager, ILogger<LogoutModel> logger,

            IIdentityServerInteractionService interaction)

        {

            _signInManager = signInManager;

            _logger = logger;

            _interaction = interaction;

        }


        public async Task<IActionResult> OnGet(string logoutId)

        {

            return await OnPost(logoutId);

        }


        public async Task<IActionResult> OnPost(string logoutId)

        {

            await _signInManager.SignOutAsync();

            _logger.LogInformation("User logged out.");

            var r = await _interaction.GetLogoutContextAsync(logoutId);

            if (r.PostLogoutRedirectUri == null)

            {

                return Redirect("/");

            }

            return Redirect(r.PostLogoutRedirectUri);

        }


查看完整回答
反对 回复 2021-11-21
?
繁花不似锦

TA贡献1851条经验 获得超4个赞

我遇到了同样的问题,为我解决了它,并决定将我的答案放在这里供其他人查看。

解决方案:在 IdentityServer4 内部,快速启动项目逻辑已经存在,可以根据用户需要对其进行配置。

  1. 打开 SolutionName/Quickstart/Account/AccountOptions.cs

  2. ShowLogoutPrompt设置为 false

  3. AutomaticRedirectAfterSignOut设置为 true

//img1.sycdn.imooc.com//6199f26e0001688614380475.jpg

查看完整回答
反对 回复 2021-11-21
  • 3 回答
  • 0 关注
  • 166 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信