猿问

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

我试图让 IdentityServer4 在新的 .NET Core 2.1 应用程序中工作(它在 .NET Core 2.0 应用程序中完美运行)。我尝试了以下方法:


1)下载这个项目,即IdentityServer4应用:https : //github.com/ghstahl/IdentityServer4-Asp.Net-2.1-Identity-Examples/tree/e0aeeff7e078aa082c8e16029dd2c220acc77d7b


2)下载这个项目,它是使用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 中注销(第一点)。


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


心有法竹
浏览 167回答 3
3回答

喵喔喔

在位于脚手架 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){&nbsp; &nbsp; await _signInManager.SignOutAsync();&nbsp; &nbsp; // ...}这个调用SignOutAsync完全符合它的建议:它使您退出 IS4 本身。但是,在您当前的工作流程中,OnPost不会调用此处理程序。该OnGet处理器被间接调用当您使用Logout的MVC应用程序,因为我已经提到过。现在,如果您查看Quickstart.UI项目中 IS4 注销的控制器/操作实现,您会发现它本质上是将GET请求传递给POST请求。这是代码,删除了注释:[HttpGet]public async Task<IActionResult> Logout(string logoutId){&nbsp; &nbsp; var vm = await BuildLogoutViewModelAsync(logoutId);&nbsp; &nbsp; if (vm.ShowLogoutPrompt == false)&nbsp; &nbsp; &nbsp; &nbsp; return await Logout(vm);&nbsp; &nbsp; return View(vm);}注销时,有一个设置可控制是否应首先提示用户确认是否要注销。这主要是这段代码所处理的 -POST如果不需要提示,它会直接将其传递给请求处理程序。这是 的代码片段POST:[HttpPost][ValidateAntiForgeryToken]public async Task<IActionResult> Logout(LogoutInputModel model){&nbsp; &nbsp; var vm = await BuildLoggedOutViewModelAsync(model.LogoutId);&nbsp; &nbsp; if (User?.Identity.IsAuthenticated == true)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; await HttpContext.SignOutAsync();&nbsp; &nbsp; &nbsp; &nbsp; // ...&nbsp; &nbsp; }&nbsp; &nbsp; // ...&nbsp; &nbsp; return View("LoggedOut", vm);}这里重要的一行是调用HttpContext.SignOutAsync- 这最终会删除 IS4 用来让您保持登录状态的 cookie。一旦它被删除,您就会退出 IS4。最终,这是您当前实现中所缺少的。在最简单的层面上,您可以通过将您的问题更新OnGet为如下所示来解决您的问题:public async Task<IActionResult> OnGet(){&nbsp; &nbsp; if (User?.Identity.IsAuthenticated == true)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; await _signInManager.SignOutAsync();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; return RedirectToPage(); // A redirect ensures that the cookies has gone.&nbsp; &nbsp; }&nbsp; &nbsp; return Page();}这不支持ShowLogoutPrompt我上面详述的选项,只是为了让这个答案更短一些。除此之外,_signInManager鉴于您在 ASP.NET Core Identity 世界中,它仅用于注销。我鼓励你去探索从完整的源代码Quickstart.UI执行情况,以便支持ShowLogoutPrompt,returnUrl等等-我不可能做到这一点这里没有写一本书。

www说

简单的注销功能是可能的,如下所示:&nbsp; &nbsp; &nbsp; &nbsp; private readonly SignInManager<IdentityUser> _signInManager;&nbsp; &nbsp; &nbsp; &nbsp; private readonly ILogger<LogoutModel> _logger;&nbsp; &nbsp; &nbsp; &nbsp; private readonly IIdentityServerInteractionService _interaction;&nbsp; &nbsp; &nbsp; &nbsp; public LogoutModel(SignInManager<IdentityUser> signInManager, ILogger<LogoutModel> logger,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IIdentityServerInteractionService interaction)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _signInManager = signInManager;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _logger = logger;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _interaction = interaction;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; public async Task<IActionResult> OnGet(string logoutId)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return await OnPost(logoutId);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; public async Task<IActionResult> OnPost(string logoutId)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; await _signInManager.SignOutAsync();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _logger.LogInformation("User logged out.");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var r = await _interaction.GetLogoutContextAsync(logoutId);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (r.PostLogoutRedirectUri == null)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return Redirect("/");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return Redirect(r.PostLogoutRedirectUri);&nbsp; &nbsp; &nbsp; &nbsp; }

繁花不似锦

我遇到了同样的问题,我为我解决了它,并决定将我的答案放在这里供其他人查看。解决方案:在 IdentityServer4 内部,快速启动项目逻辑已经存在,可以根据用户需要对其进行配置。打开 SolutionName/Quickstart/Account/AccountOptions.cs将ShowLogoutPrompt设置为 false将AutomaticRedirectAfterSignOut设置为 true
随时随地看视频慕课网APP
我要回答