我正在研究一个使用ASP.net Core 2.1和IdentityServer4库的Identity Server实现。在OAuth2协议的上下文中,一旦客户通过服务器提供的Web表单提供了他/她的登录凭据,身份服务器就以返回AuthorizationCode的方式实现。服务器将代码返回到客户第一次提出登录请求时提供的redirectURI(请参见下面显示的示例登录请求)。
1)示例场景
示例登录请求:
http://exampleABC.com:5002/connect/authorize?client_id=XYZ&scope=myscope&response_type=code&redirect_uri=http://exampleXYZ.com
以上在浏览器中发出类似请求后,浏览器将打开一个客户端登录页面,要求用户输入其客户ID和密码。然后,打开一个SMS令牌页面,客户在此输入他在手机上收到的SMS。然后,客户在浏览器中输入SMS。最后,服务器将客户的浏览器重定向到redirectURI上的页面,在该页面上浏览器在地址栏中显示AuthorizationCode(即代码),如下所示:
https://exampleXYZ.com/?code=89c0cbe1a2cb27c7cd8025b6cc17f6c7cf9bc0d4583c5a63&scope=myscope
此处,代码“ 89c0cbe1a2cb27c7cd8025b6cc17f6c7cf9bc0d4583c5a63”现在可用于从身份服务器请求AccessToken。
2)问题声明
如果我在同一客户端浏览器(例如chrome)中重新发出上述指示的登录请求示例,则浏览器会立即将用户重定向到redirectURI,而无需重新询问客户端登录凭据。这是一个问题,因为考虑到可能存在具有不同登录凭据的客户,每次发出登录请求时,我都必须打开一个新的登录屏幕。因此,我在IdentityServer实现中提供了注销端点,该端点打算清除整个客户端缓存,然后注销客户,如以下代码块所示。在这里,我先删除cookie,然后创建一个具有相同密钥和过期日期的新cookie,以便从服务器浏览器缓存中将cookie从客户端浏览器缓存中删除。我的目的是在发出注销请求时始终将登录Web表单始终放在浏览器中,并且不进行缓存,以便每次有新客户到达时都显示登录表单。
public async Task<IActionResult> Logout()
{
var vm = await BuildLoggedOutView();
string url = Url.Action("Logout", new { logoutId = vm.LogoutId });
try
{
if (HttpContext.Request != null && HttpContext.Request.Cookies != null && HttpContext.Request.Cookies.Keys != null && HttpContext.Request.Cookies.Keys.Count > 0)
{
foreach (var key in _accessor.HttpContext.Request.Cookies.Keys)
{
//!!!! Cookie Removal !!!!!!
//Here I delete the cookie first and then recreate it
//with an expiry date having the day before.
_accessor.HttpContext.Response.Cookies.Delete(key);
_accessor.HttpContext.Response.Cookies.Append(
key,
string.Empty,
new CookieOptions()
{
Expires = DateTime.Now.AddDays(-1)
});
}
}
//!!!! Explicit sign out!!!!!!
await _accessor.HttpContext.SignOutAsync();
}
catch (NotSupportedException ex) // this is for the external providers that don't have signout
{
}
catch (InvalidOperationException ex) // this is for Windows/Negotiate
{
}
return View("Logged out", vm);
}
3)问题:
尽管我删除了cookie并在服务器端覆盖了它们,但是客户端浏览器仍继续返回到重定向uri的页面,在页面中显示了新的授权代码,而没有强制客户登录(这是不希望的)。因此,我的问题是上述代码块中缺少什么?它看起来既没有使用旧的到期日期覆盖Cookie,也没有显式调用SignoutAsync方法无助于完全注销客户。您是否可以建议一些更明确的策略,以便在注销后完全清除客户端和服务器端的所有内容?
答案 0 :(得分:2)
我也遇到了同样的问题,即Cookie无法正确删除。就我而言,这是因为我定义了身份验证Cookie的特定路径。假设我的路径为/path
,在这种情况下,您必须在删除操作中指定相同的路径:
foreach (var cookie in Request.Cookies.Keys)
{
Response.Cookies.Delete(cookie, new CookieOptions()
{
Path = "/path",
// I also added these options, just to be sure it matched my existing cookies
Expires = DateTimeOffset.Now,
Secure = true,
SameSite = SameSiteMode.None,
HttpOnly = true
});
}
此外,我不知道.Append()
是否必要。在我的情况下,通过使用.Delete()
它已经发送了一个set-cookie头。