ASP.net Core 2.1和IdentityServer4-客户端和服务器端Cookie删除

时间:2019-10-31 07:24:29

标签: asp.net-core cookies asp.net-identity identityserver4 asp.net-core-2.1

我正在研究一个使用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方法无助于完全注销客户。您是否可以建议一些更明确的策略,以便在注销后完全清除客户端和服务器端的所有内容?

1 个答案:

答案 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头。