跨子域共享 ASP.NET cookie

34

我有两个站点,都在同一个域上,但是有不同的子域。

  • site1.mydomain.example
  • site2.mydomain.example

一旦我在两个站点中进行验证,然后查看随后请求中包含的cookie,它们对于每个站点都是相同的。

然而,如果我先登录第一个站点,然后导航到另一个站点,我期望我的来自站点1的cookie将与发送到站点2的请求一起发送,但事实并非如此。这是我的cookie的属性。

登录Site1后,该cookie现在存在

Name = MySite
Domain =
Has Keys = False
HttpOnly = False
Path = /
Value = 1C41854066B03D8CC5679EA92DE1EF427DAC65D1BA0E672899E27C57245C1F0B7E93AB01B5563363AB4815A8F4BDE9D293FD261E03F8E60B8497ABBA964D8D315CCE1C8DD220C7176E21DC361935CF6
Expires = 1/1/0001 12:00:00 AM

登录Site2后,这些cookie将存在。

Name = MySite
Domain =
Has Keys = False
HttpOnly = False
Path = /
Value =    C8C69F87F993166C4D044D33F21ED96463D5E4EB41E1D986BF508DA0CBD5C2CA7D782F59F3BC96871108997E899FF7401C0D8615705BDB353B56C7E164D2302EE6731F41705016105AD99F4E0578ECD2
Expires = 1/1/0001 12:00:00 AM

我已经为每个站点设置了域名,但它不会显示在请求cookie中,因为它只在客户端上需要。

我已确保每个表单的设置都相同。

我已确保两个Web配置文件中我的机器密钥设置相同。

我不知道为什么这不起作用。就我所知,当它们都使用相同的身份验证cookie时,一个子域和另一个子域之间的客户端发送cookie时包含什么内容?

如果您想查看更多信息,请在下面留言。我已经苦恼了两天。根据这篇文章,这应该可以工作。

添加的代码:

这是我的身份验证的配置文件设置。这在两个网站中都使用。

<authentication mode="Forms">
    <forms loginUrl="~/Account/LogOn"
       defaultUrl="~/Home/Index"
       name="MySite"
       protection="All"
       path="/"
       domain="mydomain.example"
       enableCrossAppRedirects="true"
       timeout="2880"
/>

这是我在Site1中创建cookie的代码。

//Add a cookie that the Site2 will use for Authentication
var cookie = FormsAuthentication.GetAuthCookie(userName, true);
cookie.Name = "MySite";
cookie.HttpOnly = false;
cookie.Expires = DateTime.Now.AddHours(24);
cookie.Domain = "mydomain.example";
HttpContext.Response.Cookies.Add(cookie);
HttpContext.Response.Redirect(site2Url,true);

更新2:

在测试时,我注意到了一些奇怪的事情。当我向site1的响应中添加一个cookie时,它会被添加到此目录中... C:\Users\jreddy\AppData\Roaming\Microsoft\Windows\Cookies

当我向site2的响应中添加一个cookie时,它将被添加到此目录中... C:\Users\jreddy\AppData\Roaming\Microsoft\Windows\Cookies\Low

这可能是我的问题所在。难道我的一个站点包含在本地内部网区域中吗?

更新3:找到问题,解决方案未知 似乎我的问题与我的第二个站点是本地内部网区域的一部分有关。如果我使用Firefox访问Site1,它可以工作,但是我必须输入我的Windows凭据。如果我通过IE访问,则我的凭据会自动获取,但是无法读取site2的cookie。我可能会在另一个问题中提问。


1
域名应该是 domain=".mydomain.com"(注意前面的点号),而不是 domain="mydomain.com"。 - roman m
1
对我来说,我的问题是一个我忘记了的Web.config Debug转换 -_- - David d C e Freitas
4个回答

20

在两个子域网站的每个Cookie中,将Domain属性设置为.mydomain.example。例如:

Response.Cookies["test"].Value = "some value";
Response.Cookies["test"].Domain = ".mysite.example";

在网站A中:

HttpCookie hc = new HttpCookie("strName", "value");
hc.Domain = ".mydomain.example"; // must start with "."
hc.Expires = DateTime.Now.AddMonths(3);
HttpContext.Current.Response.Cookies.Add(hc);

在网站B中:

HttpContext.Current.Request.Cookies["strName"].Value

我尝试过了,但没有起作用。我还尝试创建第二个cookie,保存一个随机值,而不是“FormsAuthentication” cookie。但我的第二个站点也没有检测到它。 - Jeff Reddy
1
我尝试了你添加的内容,几乎是逐字逐句地照着做,但仍然没有成功。最初我是想共享一个身份验证 cookie,但现在我只想让 "strName" 和 "value" 能够被传递。当我到达第一个站点并按照你的建议创建该 cookie 时,它总是在将来的请求中发送到该站点(站点1),但站点2 却从未收到它。 - Jeff Reddy
首先,我确定这段代码是正确的并且能正常运行,我在我的项目中使用它。其次,处理 Cookie 有很多条件,所以请确保您已清除旧 Cookie,并通过在浏览器中检查带有域值为“.mydomain.com”和足够过期时间的 Cookie 来确保 Cookie 被成功创建。然后进行最后一步,按照我告诉你的代码来读取它……请告诉我在哪一步解决了这个问题。问候 - Mhmd
我将尝试使所有的cookie过期。我一直在手动从本地目录中删除它们。我认为代码是正确的,但有些与我的网站相关的独特问题阻止了cookie被发送到site2的请求中。 - Jeff Reddy
请使用火狐浏览器,并安装一个浏览Cookie的工具,就像我告诉你的那样,如果你的Cookies已经被创建,告诉我一声 :) - Mhmd
显示剩余4条评论

9
添加新的 cookie 并指定域名的方式如下:
HttpCookie cookie = new HttpCookie("cookiename", "value");
cookie.Domain = "domain.example";

对于表单身份验证,请在web.config中设置以下内容

<forms name=".ASPXAUTH"
       loginUrl="login.aspx"
       protection="All"
       timeout="30"
       path="/"
       requireSSL="false"
       domain="domain.example">
</forms>

这个cookie将可以被所有子域名访问。

为了让每个域名都能解密此cookie,所有web.config文件必须使用相同的加密/解密算法和密钥。(如何创建机器密钥

示例:

// do not wrap these values like this in the web.config
// only wrapping for code visibility on SO
<machineKey
  validationKey="21F090935F6E49C2C797F69BBAAD8402ABD2EE0B667A8B44EA7DD4374267A75
                 D7AD972A119482D15A4127461DB1DC347C1A63AE5F1CCFAACFF1B72A7F0A281
                 B"
  decryptionKey="ABAA84D7EC4BB56D75D217CECFFB9628809BDB8BF91CFCD64568A145BE59719
                 F"
  validation="SHA1"
  decryption="AES"
/>

为了更容易部署,这些值可以存储在一个单独的文件中:
<machineKey configSource="machinekey.config"/>

为了增加安全性,您还可以对机器密钥进行加密以提高保护级别。.


我添加了用于两个网站的身份验证配置设置,以及 cookie 创建代码。 - Jeff Reddy
我尝试在site1的响应中添加另一个cookie,类似于你的方法。我只是将其命名为test,赋予随机值,然后确保我设置了域。一旦设置完成,访问Site1时会得到该cookie,但访问site2时则无法获取该cookie。 - Jeff Reddy
请查看此链接http://www.15seconds.com/issue/971108.htm或SO问题-https://dev59.com/CXI95IYBdhLWcg3wvwsQ - Prasanth
我从这两个网站中获取了示例和建议,但仍无法在site2中获取cookies。 - Jeff Reddy
1
对于表单身份验证 cookie,值得一提的是,如果有多个应用程序,则机器密钥应该匹配。此外,我不得不明确设置 compatibilityMode 以使事情在 IIS8 中顺利运行。http://msdn.microsoft.com/en-us/library/system.web.configuration.machinekeysection.compatibilitymode.aspx - Jim Geurts

4
如果您在所有子域上使用Forms身份验证,则只需将domain=".mydomain.example"属性添加到<forms>节点中的web.config中即可。请注意.mydomain.example中的前导句点。这个简单的更改本身就可以使您的身份验证cookie在所有子域中有效;不需要手动设置任何cookie。

1
我创建了一个HttpContext扩展方法,用于编写子域安全的cookie。

博客文章和讨论

public static class HttpContextBaseExtenstions
{
    public static void SetSubdomainSafeCookie(this HttpContextBase context, string name, string value)
    {
        var domain = String.Empty;

        if (context.Request.IsLocal)
        {
            var domainSegments = context.Request.Url.Host.Split('.');
            domain = "." + String.Join(".", domainSegments.Skip(1));
        }
        else
        {
            domain = context.Request.Url.Host;
        }

        var cookie = new HttpCookie(name, value)
        {
            Domain = domain
        };

        context.Response.SetCookie(cookie);
    }
}

// usage
public class MyController : Controller
{
    public ActionResult Index()
    {
        this.Context.SetSubdomainSafeCookie("id", Guid.NewGuid().ToString());
        return View();
    }
}

这行代码context.Request.IsLocal的含义是什么?什么时候IsLocal会为真? - Mou
当您在本地主机上运行应用程序时 - Nick

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接