FormsAuthentication.SetAuthCookie不能设置Path或Domain?

9

我有一个Web应用程序可以安装在许多域和路径上。

所以:

  • client1Name.{mySite.com}
  • client2Name.{mySite.com}
  • demo.{mySite.com}/prospect1Name
  • demo.{mySite.com}/prospect2Name
  • demo.{mySite.com}/prospect3Name

所有这些都是相同代码的单独应用程序实例。

问题在于,如果客户端登录到client1Name.{mySite.com},然后访问其他站点,他们的浏览器将发送验证cookie。

在所有情况下,FormsAuthentication.SetAuthCookie都不会设置PathDomain

我期望的是:

  • client1Name.{mySite.com} - Domain = client1Name.{mySite.com}Path = /
  • client2Name.{mySite.com} - Domain = client2Name.{mySite.com}Path = /
  • demo.{mySite.com}/prospect1Name - Domain = demo.{mySite.com}Path = /prospect1Name
  • demo.{mySite.com}/prospect2Name - Domain = demo.{mySite.com}Path = /prospect2Name
  • demo.{mySite.com}/prospect3Name - Domain = demo.{mySite.com}Path = /prospect3Name

我可以手动覆盖.NET的行为以显式设置这些内容,但我不确定为什么需要这样做-当设置身份验证cookie时,这应该是默认行为或至少可以设置的选项,而无需重写大块代码。

我有什么遗漏吗?是否有一种方法可以使FormsAuthentication.SetAuthCookie设置PathDomain

如果没有,最好的方法是动态读取最佳的PathDomain是什么?同一代码必须在所有站点上运行,我不想添加更多的配置键。

更新

这是我的当前解决方案:

// replacement for FormsAuthentication.SetAuthCookie(user.UserName, false);
// as that fails to limit the cookie by domain & path and fails.

var cookie = FormsAuthentication.GetAuthCookie(username, false);
cookie.HttpOnly = true;
cookie.Path = this.Request.ApplicationPath;
cookie.Secure = string.Equals("https", this.Request.Url.Scheme, StringComparison.OrdinalIgnoreCase);

// the browser will ignore the cookie if there are fewer than two dots
// see cookie spec - http://curl.haxx.se/rfc/cookie_spec.html
if (this.Request.Url.Host.Split('.').Length > 2)
{
    // by default the domain will be the host, so www.site.com will get site.com
    // this may be a problem if we have clientA.site.com and clientB.site.com
    // the following line will force the full domain name
    cookie.Domain = this.Request.Url.Host;
}

this.Response.Cookies.Add(cookie);

然而,这似乎是在做很多绕路的事情,FormsAuthentication.SetAuthCookie应该能够完成。这真的是最好的方法吗?


你为什么会期望在cookie中看到这些内容呢?我的期望是域名应该是{mySite.com},路径应该始终为/ - Joel Etherton
@Joel Etherton - 无论它是否是默认行为,看起来在_{mySite.com}/client1Name_和_{mySite.com}/client2Name_不共享身份验证票据并不是一件很奇怪的事情。我不应该不得不替换整个方法来实现这一点。 - Keith
这些文件夹的分离是否也代表着完整应用程序的分离? - Joel Etherton
3个回答

9
我必须进行大量的研究,但看起来FormsAuthentication.SetAuthCookie不支持这个原因是因为它不应该支持 - IIS永远不应该在身份验证cookie上设置路径,这就是为什么......
cookie路径区分大小写,所以:
- http://site/path - http://site/PATH 对于浏览器来说是两个不同的cookie - 无论是IE、FX、Safari、Opera还是Chrome都不会将/PATH的cookie发送到/path或反之亦然。
IIS不区分大小写,但总是将URL重置为ASP应用程序名称的大小写。
这意味着如果IIS应用程序被称为“PATH”,用户进入http://site/path,那么他们将被重定向到http://site/PATH/LogOn?ReturnUrl=/path来进行登录。
成功登录后,用户将被重定向回指定的ReturnUrl,因此:
1. 用户进入http://site/path 2. 被IIS发送到http://site/PATH/LogOn?ReturnUrl=/path 3. 输入登录详细信息并提交 4. 响应将cookie设置为/PATH,位置设置为/path(由ReturnUrl定义) 5. 重定向回http://site/path 6. 浏览器无法识别/path,它只有一个/PATH的cookie,因此什么也不发送! 7. 没有cookie发送到应用程序,因此它会提供一个重定向回http://site/PATH/LogOn?ReturnUrl=/path 8. 回到步骤2并重复。
这为用户创建了一个问题,如果他们将http://site/path作为应用程序的URL,则永远不会出现登录状态。
此外,如果他们已经登录到http://site/PATH并被发送一个URL,例如http://site/path/resource/id的电子邮件,他们将被要求重新登录,并且无法进入新路径。
这意味着,除非您需要/PATH/path成为完全不同的站点(在某些UNIX环境之外不太可能),否则您不应该在身份验证cookie上设置路径属性。

3

Cookie是在域级别设置的,是静态的。默认情况下,FormsAuthentication使用TLD(顶级域名)来设置它,在这种情况下是{mySite.com}。为了使其具体化,您需要告诉它使用client1Name.{mySite.com}。但是这样做会将cookie限制为该特定子域,子域client2Name将无法访问cookie。

Cookie的路径限制了cookie适用的子文件夹。在FormsAuthentication的情况下,再次默认设置为根目录/。您可以手动将其设置为其他内容,但是通过将其设置为/prospect1Name,所有其他文件夹立即失去对cookie的访问权限。

我不确定您正在尝试使用这些约束产生什么行为,但是使用cookie可能不是合适的工具。操纵域将限制您的身份验证控件的有效性(除非这正是您要做的)。


1
抱歉,我认为我已经非常清楚了 - client1Name.{mySite.com} 的 cookies 不应该发送到 _client2Name.{mySite.com}_,反之亦然。我知道你可以手动设置 cookie,但这样就无法使用 FormsAuthentication.SetAuthCookie - Keith
@Keith:如果您想在域之间提供分离,只需在FormsAuthentication元素的web.config属性中设置EnableCrossAppRedirects=false即可。对于每个文件夹,您还可以在同一元素中指定Path属性,但这需要应用于每个单独的应用程序/文件夹。我以前从未尝试过从子文件夹内覆盖父FormsAuthentication元素,但我相信这是可能的。 - Joel Etherton
感谢您的帮助(+1) - 结果发现您不能这样做的原因是您真的不应该这样做(我必须通过艰难的方式弄清楚这一点)。我在另一个答案中详细解释了原因。 - Keith
我来晚了,但这篇文章帮助我解决了在同一主机上的PROD和TEST Web应用程序中出现的问题:登录TEST会使您退出PROD,反之亦然,因为它们会覆盖彼此的身份验证cookie。我尝试在“forms”配置节点中使用enableCrossAppRedirects="false",但对我没有起作用,因为(显然根据名称)它是用于跨应用程序传递身份验证的。要解决问题,我所要做的就是将每个应用程序的“web.config”中的“forms”“name”属性更改为唯一值,而不是默认值“.ASPXAUTH”,然后就可以了!傻瓜!我总是认为它必须是“.ASPXAUTH”(错误的假设)。 - nothingisnecessary

1
很久以后,我又遇到了同样的问题。我尝试了各种方法,却没有找到可行的解决方案。直到我意识到我可以使用cookie名称而不是路径,从而保持Path = "/"的良好行为,同时具有不同的basePath访问。(您仍然需要能够通过环境变量或其他方式(而不是从URL中)检索应用程序名称。)
只需在配置中添加类似的内容
builder.Services.ConfigureApplicationCookie(options =>
{
    // someconfigs options
    ... 

    options.Cookie.Name = $".AspNetCore.Identity.Application.{AppName}"; // Important thing to dissociate apps (find your appname by search in iis before or environment variable)
    options.Cookie.Path = "/"; // Important thing
});

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