我正在尝试让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应用中包含的“启动”(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中注销(第一点)。
为什么最终用户必须注销两次?
答案 0 :(得分:3)
在Account/Logout
页面中,该页面位于脚手架的ASP.NET Core身份验证代码中的Areas/Identity/Account/Logout.cshtml.cs
下,其中有一个OnGet
处理程序,如下所示:
public void OnGet() { }
因为这使用的是ASP.NET Core Razor页面,所以所有要做的就是呈现相应的Logout.cshtml
页面。在您的示例中,当您在MVC应用程序中点击Logout
时,它将清除自己的Cookie,然后将您传递到IS4应用程序(特别是OnGet
)。由于此OnGet
处理程序为空,因此它实际上并没有做任何事情,也肯定不会使您退出IS4应用。
如果您查看OnPost
内的Logout.cshtml.cs
处理程序,就会发现它看起来像这样:
public async Task<IActionResult> OnPost(string returnUrl = null)
{
await _signInManager.SignOutAsync();
// ...
}
对SignOutAsync
的调用完全符合其建议:它使您退出IS4本身。但是,在您当前的工作流程中,未调用此OnPost
处理程序。如前所述,在MVC应用程序中使用OnGet
时会间接调用Logout
处理程序。
现在,如果您在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。删除该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
选项,只是为了使此答案短一点。除此之外,假设您在ASP.NET Core Identity世界中,它仅使用_signInManager
进行注销。
我鼓励您探索Quickstart.UI实现中的完整源代码,以支持ShowLogoutPrompt
,returnUrl
等-在这里,如果没有编写书。
答案 1 :(得分:1)
可以实现简单的注销功能,如下所示:
import math
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
nu = []
b = [0.1 + i / 100 for i in range(0, 510)]
d = 0.1
for beta in b:
nu.append( math.sqrt(1+(2*d*beta)**2)/ math.sqrt((1-beta**2)**2+(2*d*beta)**2))
#turned d into array of length 510 with 0.1 for each value
d = np.ones(510)*0.1
fig = plt.figure()
ax = Axes3D(fig)
ax.plot(b, d, nu)
plt.show()
答案 2 :(得分:0)