我有一个带有自定义角色和用户存储的Asp.Net MVC应用程序(版本6.0.0-rc1-final)。经过一些struggling我终于可以创建一个有效的登录机制。但是我现在有麻烦来创建一个干净的注销。我的控制器当前的注销代码是什么样的:
public async Task<ActionResult> Logout()
{
if (User.Identity.IsAuthenticated)
{
await SignInManager.SignOutAsync();
}
return RedirectToAction("Index", "App");
}
此代码存在的问题是,未删除一个Cookie: .AspNet.Microsoft.AspNet.Identity.Application
只要我不手动删除cookie,应用程序就处于脏状态并抛出空指针异常,因为 User.Identity 为空。
我找到了描述类似场景的question on stackoverflow。但是那里的解决方案对我来说并不合适,因为我使用的MVC 6已经不再有System.Web了。
我也有一个样本解决方案,它可以正常工作。在此解决方案中,永远不会创建所提到的cookie。也许正确的解决方案不是在注销后删除cookie,而是为了防止以某种方式创建cookie。
答案 0 :(得分:1)
我可以在注销后通过在注销操作后手动删除cookie来修复应用程序的脏状态:
public async Task<ActionResult> Logout()
{
if (User.Identity.IsAuthenticated)
{
await SignInManager.SignOutAsync();
}
foreach (var key in HttpContext.Request.Cookies.Keys)
{
HttpContext.Response.Cookies.Append(key, "", new CookieOptions() { Expires = DateTime.Now.AddDays(-1) });
}
return RedirectToAction("Index", "App");
}
由于cookie无法直接从服务器中删除,我只是用已经过期的日期覆盖现有的cookie。
答案 1 :(得分:1)
问题是您的RedirectToAction
会将重定向覆盖到SignOutAsync
发出的Identity Server结束网址。
(微软的HaoK对同一问题的解释同样为here。)
修改:解决方案是在AuthenticationProperties
对象中发送带有最终SignOutAsync
的重定向网址:
// in some controller/handler, notice the "bare" Task return value
public async Task LogoutAction()
{
// SomeOtherPage is where we redirect to after signout
await MyCustomSignOut("/SomeOtherPage");
}
// probably in some utility service
public async Task MyCustomSignOut(string redirectUri)
{
// inject IHttpContextAccessor to get "context"
await context.SignOutAsync("Cookies");
var prop = new AuthenticationProperties()
{
RedirectUri = redirectUri
});
// after signout this will redirect to your provided target
await context.SignOutAsync("oidc", prop);
}
答案 2 :(得分:0)
除了已经提到的所有内容之外,还要确保在scheme
和SignInAsync
的调用中没有省略SignOutAsync
参数,并且您将相同的值传递给两者。例如:
HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);
和
HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
因此,在此示例中,方案为CookieAuthenticationDefaults.AuthenticationScheme
。在我的情况下,我忘记将其传递给SignOutAsync
,而事实上显而易见的是,我花了更长的时间才愿意让我跟踪。
答案 3 :(得分:0)
另一个可能导致身份服务器cookie留在客户端上的陷阱是注销失败。注销失败的一个典型原因是客户端的PostLogoutRedirectUris配置错误。
从客户端看不到注销失败,endsession
调用返回200 OK,以及logout
调用。
但是,您的身份服务器日志上会显示注销失败的踪迹。