当前位置: 首页 > 知识库问答 >
问题:

ASP。NET\u SessionId OWIN Cookies不发送到浏览器

郎鹤龄
2023-03-14

我在使用Owin cookie身份验证时遇到了一个奇怪的问题。

当我启动IIS服务器时,身份验证在IE/Firefox和Chrome上运行得非常好。

我开始在不同的平台上进行身份验证和登录测试,发现了一个奇怪的错误。Owin框架/IIS偶尔不会向浏览器发送任何cookie。我会输入正确的用户名和密码,代码运行时不会将cookie发送到浏览器。如果我重新启动服务器,它就会开始工作,然后在某个时候我会尝试登录,再次停止发送cookie。跳过代码不会执行任何操作,也不会引发任何错误。

 app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationMode = AuthenticationMode.Active,
            CookieHttpOnly = true,
            AuthenticationType = "ABC",
            LoginPath = new PathString("/Account/Login"),
            CookiePath = "/",
            CookieName = "ABC",
            Provider = new CookieAuthenticationProvider
               {
                  OnApplyRedirect = ctx =>
                  {
                     if (!IsAjaxRequest(ctx.Request))
                     {
                        ctx.Response.Redirect(ctx.RedirectUri);
                     }
                 }
               }
        });

在我的登录过程中,我有以下代码:

IAuthenticationManager authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
                            authenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);

var authentication = HttpContext.Current.GetOwinContext().Authentication;
var identity = new ClaimsIdentity("ABC");
identity.AddClaim(new Claim(ClaimTypes.Name, user.Username));
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.User_ID.ToString()));
identity.AddClaim(new Claim(ClaimTypes.Role, role.myRole.ToString()));
    authentication.AuthenticationResponseGrant =
        new AuthenticationResponseGrant(identity, new AuthenticationProperties()
                                                   {
                                                       IsPersistent = isPersistent
                                                   });

authenticationManager.SignIn(new AuthenticationProperties() {IsPersistent = isPersistent}, identity);

更新1:问题的一个原因似乎是当我向会话添加项目时,问题开始了。添加一些简单的内容,如会话。Content[“ABC”]=123似乎产生了问题。

我能做的如下:1)(Chrome)当我登录时,我得到了ASP。NET\u SessionId我的身份验证cookie。2) 我转到设置会话的页面。目录3) 打开新浏览器(Firefox)并尝试登录,但它不会收到ASP。NET\u SessionId也没有获得身份验证Cookie 4),而第一个浏览器具有ASP。NET\u SessionId它继续工作。从我删除这个cookie的那一刻起,它就与我正在处理的所有其他浏览器(ip地址10.x.x.x)和localhost)存在相同的问题。

更新2:在使用OWIN进行身份验证之前,首先在我的登录加载页上强制创建ASPNET\u SessionId。

1)在我使用OWIN进行身份验证之前,我在登录页面上随机创建了一个会话。内容值来启动ASP。NET_SessionId2)然后我进行身份验证并进行进一步的会话3)其他浏览器现在似乎可以工作了

这很奇怪。我只能得出结论,这与ASP和OWIN认为他们在不同的领域或类似的东西有关。

更新3-两者之间的奇怪行为。

发现了其他奇怪行为-Owin和ASP会话超时不同。我看到的是,通过某种机制,我的Owin会话比我的ASP会话活得更长。因此,登录时:1。)我有一个基于Cooked的auth会话2。)我设置了几个会话变量

我的会话变量(2)在owin cookie会话变量强制重新登录之前“死亡”,这会导致整个应用程序出现意外行为。(人员已登录但未真正登录

更新3B

经过一番挖掘,我在一个页面上看到了一些评论,说“表单”身份验证超时和会话超时需要匹配。我认为这两者通常是同步的,但无论出于什么原因,两者都不同步。

解决方法摘要

1) 始终在身份验证之前先创建会话。基本上,在启动应用程序时创建会话<代码>会话[“解决方法”]=0

2) [实验性]如果您坚持使用cookie,请确保您的OWIN超时/长度比您在web中的sessionTimeout长。配置(测试中)

共有3个答案

傅越
2023-03-14

从@TomasDolezal的伟大分析开始,我看了一下Owin和系统。Web源。

问题是这个系统。Web有自己的cookie信息主源,而不是Set cookie标头。Owin只知道Set Cookie标头。解决方法是确保Owin设置的任何cookie也在HttpContext中设置。现在的回答Cookie收集。

我已经做了一个小中间件(源代码,nuget),它正是这样做的,它打算放在cookie中间件注册的正上方。

app.UseKentorOwinCookieSaver();

app.UseCookieAuthentication(new CookieAuthenticationOptions());
解鸿运
2023-03-14

简而言之。NET cookie manager将赢得OWIN cookie manager并覆盖OWIN层上设置的cookie。修复方法是使用SystemWebCookieManager类,该类是作为Katana项目的解决方案提供的。您需要使用这个类或类似的类,这将迫使OWIN使用。NET cookie管理器,因此不存在不一致:

public class SystemWebCookieManager : ICookieManager
{
    public string GetRequestCookie(IOwinContext context, string key)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }

        var webContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
        var cookie = webContext.Request.Cookies[key];
        return cookie == null ? null : cookie.Value;
    }

    public void AppendResponseCookie(IOwinContext context, string key, string value, CookieOptions options)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }
        if (options == null)
        {
            throw new ArgumentNullException("options");
        }

        var webContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);

        bool domainHasValue = !string.IsNullOrEmpty(options.Domain);
        bool pathHasValue = !string.IsNullOrEmpty(options.Path);
        bool expiresHasValue = options.Expires.HasValue;

        var cookie = new HttpCookie(key, value);
        if (domainHasValue)
        {
            cookie.Domain = options.Domain;
        }
        if (pathHasValue)
        {
            cookie.Path = options.Path;
        }
        if (expiresHasValue)
        {
            cookie.Expires = options.Expires.Value;
        }
        if (options.Secure)
        {
            cookie.Secure = true;
        }
        if (options.HttpOnly)
        {
            cookie.HttpOnly = true;
        }

        webContext.Response.AppendCookie(cookie);
    }

    public void DeleteCookie(IOwinContext context, string key, CookieOptions options)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }
        if (options == null)
        {
            throw new ArgumentNullException("options");
        }

        AppendResponseCookie(
            context,
            key,
            string.Empty,
            new CookieOptions
            {
                Path = options.Path,
                Domain = options.Domain,
                Expires = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc),
            });
    }
}

在应用程序启动时,只需在创建OWIN依赖项时分配它:

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    ...
    CookieManager = new SystemWebCookieManager()
    ...
});

这里提供了一个类似的答案,但它不包括解决问题所需的所有代码库,因此我认为有必要将其添加到这里,因为与Katana项目的外部链接可能会中断,并且应该在这里作为解决方案进行完整记录。

段干德泽
2023-03-14

我遇到了同样的问题,并将其原因追溯到OWIN ASP。NET托管实现。我会说这是一只虫子。

一些背景知识

我的发现基于以下程序集版本:

  • 微软。Owin,版本=2.0.2.0,文化=中性,PublicKeyToken=31bf3856ad364e35
  • 微软。Owin。主机。SystemWeb,版本=2.0.2.0,文化=中性,PublicKeyToken=31bf3856ad364e35
  • Web,版本=4.0.0.0,文化=中性,PublicKeyToken=b03f5f7f11d50a3a

OWIN使用自己的抽象来处理响应cookie(Microsoft.OWIN.ResponseCookieCollection)。此实现直接包装响应标头集合,并相应地更新集合Cookie标头。OWIN ASP。NET主机(Microsoft.Owin.host.SystemWeb)只是包装系统。网状物HttpResponse及其headers集合。所以,当通过OWIN创建新的cookie时,响应集cookie头将直接更改。

但是ASP。NET还使用自己的抽象来处理响应cookie。这是作为系统向我们公开的。网状物HttpResponse。Cookies属性,并由密封类系统实现。网状物HttpCookieCollection。此实现不直接包装响应集Cookie头,而是使用一些优化和少量内部通知将其更改的状态显示给响应对象。

然后,在请求生命周期的后期,测试HttpCookieCollection更改状态(System.Web.HttpResponse.GenerateResponseHeadersForCookies()),并序列化Cookie以设置Cookie标头。如果此集合处于某个特定状态,则首先清除并从集合中存储的Cookie中重新创建整套Cookie标头。

ASP. NET会话实现使用System. Web. HttpACK. Cookies属性来存储它的ASP.NET_SessionIdcookie。ASP. NET会话状态模块(System. Web. SessionState. SessionStateModule)中也有一些基本的优化,通过名为s_sessionEverSet的静态属性实现,这是非常不言自明的。如果您曾经在应用程序中将某些内容存储到会话状态,则此模块将为每个请求做更多的工作。

回到我们的登录问题

有了所有这些片段,就可以解释您的场景。

案例1-从未设置会话

系统网状物会话状态。SessionStateModule,s\u sessionEverSet属性为false。会话状态模块和系统不生成会话id。网状物HttpResponse。未检测到Cookie收集状态已更改。在这种情况下,OWIN cookies会正确发送到浏览器并登录。

案例2-会话在应用程序中的某个位置使用,但不是在用户尝试进行身份验证之前使用

System. Web. SessionState. SessionStateModule,s_sessionEverSet属性为true。会话ID由SessionStateModule, ASP生成。NET_SessionId被添加到System. Web. HttpACK. Cookie集合中,但它会在请求生命周期后期删除,因为用户的会话实际上为空。在这种情况下,System. Web. HttpACK. Cookie集合状态被检测为已更改,并且在cookie序列化为标头值之前首先清除Set-Cookie标头。

在这种情况下,OWIN响应cookie将“丢失”,用户未经过身份验证,并被重定向回登录页面。

案例3-在用户尝试进行身份验证之前使用会话

系统网状物会话状态。SessionStateModule,s\u sessionEverSet属性为true。会话Id由SessionStateModule ASP生成。NET\u SessionId已添加到系统中。网状物HttpResponse。饼干。由于系统内部优化。网状物HttpCookieCollection和系统。网状物HttpResponse。GenerateResponseHeadersForCookies()设置Cookie标头不会首先清除,但只会更新。

在这种情况下,OWIN身份验证cookie和ASP。NET\u SessionId cookie被发送响应并登录。

Cookie的更普遍问题

正如您所看到的,问题更普遍,不限于ASP. NET会话。如果您通过Microsoft托管OWIN。Owin。主机。SystemWeb和您/某事直接使用System. Web。HttpACK。Cookie收集您面临风险。

例如,这起作用,两个cookie都正确发送到浏览器。。。

public ActionResult Index()
{
    HttpContext.GetOwinContext()
        .Response.Cookies.Append("OwinCookie", "SomeValue");
    HttpContext.Response.Cookies["ASPCookie"].Value = "SomeValue";

    return View();
}

但事实并非如此,OwinCookie“迷路了”。。。

public ActionResult Index()
{
    HttpContext.GetOwinContext()
        .Response.Cookies.Append("OwinCookie", "SomeValue");
    HttpContext.Response.Cookies["ASPCookie"].Value = "SomeValue";
    HttpContext.Response.Cookies.Remove("ASPCookie");

    return View();
}

两者都从VS2013、IISExpress和默认MVC项目模板进行了测试。

 类似资料:
  • 我们研发的App可以在用户确认访问我们的分支机构后向其发送电子邮件。当我们使用以下Gmail配置时,它可以正常工作:电子邮件:ainetwgdocs@gmail.comPasswd:XXXXX SMTP服务器:smtp.gmail.com端口:587但是,当我们尝试使用基于域的帐户时,它根本不起作用。我们使用以下参数:电子邮件:contact@ainetw.comPasswd:XXXXX SMTP

  • 当Web应用程序在Docker中被容器化时,我无法让我的ASP. NET Web应用程序提供给我的浏览器。 我正在运行一个Mac,我已经使用Visual Studio Code创建了一个ASP. NET Web应用程序。这是一个简单的开箱即用的演示,它基于“空应用程序”当运行本机(在Docker之外)时,此应用程序提供Hello World!http://localhost:5000很好。换句话说

  • 在处理 ASP 脚本时,任何没有包含在 ASP 定界符或 <SCRIPT> 标记中的文本或图形都将被简单地返回给浏览器。可以通过使用 Response 对象显示地把内容发送给浏览器。 发送内容 要将内容从 ASP 定界符内部或过程发送给浏览器,可以使用 Response 对象的 Write 方法。例如,下面的语句可以根据用户是否访问过此页而发送不同的问候语: <% If FirstTime =

  • 由于每次登录时都有大量文件下载,我正试图修复一个网络应用程序的性能。为此,我希望启用条件浏览器缓存,即,如果ETag发生变化,从服务器提供新的副本,否则使用浏览器缓存。 通过java过滤器从服务器发送的响应标头: 浏览器下次调用时,发送的请求标头为: 浏览器没有发送 If-None-Match 标头,因此用于验证 ETag 并发回 304 响应代码的服务器端代码失败,并且服务器始终将新副本发送到客

  • 现在如何将此保存到浏览器。