我的网站在 IIS 上工作正常,但 IIS Express 失败。
tl:博士;如何在同一域下的 IIS Express 中将两个单独的 .NET 4.8 Framework 应用程序配置为虚拟目录,但一个使用 Windows Auth,另一个使用 Forms Auth?现在 Windows Auth 正在覆盖它们。
我有一个带有两个虚拟目录的站点/域,每个目录都指向不同的应用程序:
- domain.com
- virualDirectory1 (/app1windows)
- virtualDirectory2 (/app2forms)
app1windows
使用 WindowsAuthentication
,从 Active Directory 获取用户身份,然后创建 FormsAuthentication
cookie。然后,该应用程序重定向到 /app2forms/handler.ashx
,后者读取 cookie,执行一些逻辑,然后设置一个新的 FormsAuthentication
cookie,其中仅包含 app2forms
中可用的附加信息。所有这些都运行良好。我什至将 HttpContext.Current.User
设置为新的 GenericPrincipal
和 FormsIdentity
。
当
/app2forms
然后尝试导航到页面并经过 Application_AuthenticateRequest
时,就会出现问题。 。 。在这里,HttpContext.Current.User.Identity
始终是System.Security.Principal.WindowsIdentity
类型,尽管事实上应该为此应用程序关闭Windows身份验证。
在我的
/app2forms
的 web.config 中,它非常清楚地指出:
<system.web>
<authentication mode="Forms">
<forms cookieless="UseCookies" name="cookieName" path"/" etc. />
...
我右键单击了
/app2forms
的项目文件,并将 Windows Authentication
显式设置为 Disabled
。
在
app2forms
的 .CSPROJ 文件中,我设置了 <IISExpressWindowsAuthentication>disabled</IISExpressWindowsAuthentication>
。
我已打开 applicationhost.config 文件并为每个虚拟目录设置唯一的
applicationPool
。
除了明确的
windowsAuthentication
之外,我的 applicationhost.config 文件中没有任何地方启用了 app1windows
。
我需要这些应用程序在同一域下同时运行,并在其 web.config 文件中设置相同的
machineKey
,否则 cookie 将无法跨应用程序识别。
为什么/如何
app2forms
在任何地方看到任何类型的 WindowsIdentity?如何让一个应用程序识别 WindowsIdentity,而另一个应用程序使用 FormsIdentity?请帮忙。
好吧,我决定顺其自然,而不是试图与之抗争。我发现@dean-harding 的这个答案建议在检测到
WindowsIdentity
时抓取表单cookie。所以这是我的解决方案:
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
if (HttpContext.Current.User != null)
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
if (HttpContext.Current.User.Identity is FormsIdentity)
{
FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity;
FormsAuthenticationTicket ticket = id.Ticket;
string userData = ticket.UserData;
string[] roles = userData.Split(',');
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(id, roles);
}
else if (HttpContext.Current.User.Identity is WindowsIdentity)
{
var oldTicket = ExtractTicketFromCookie(HttpContext.Current, FormsAuthentication.FormsCookieName);
if (oldTicket != null && !oldTicket.Expired)
{
var ticket = oldTicket;
if (FormsAuthentication.SlidingExpiration)
{
ticket = FormsAuthentication.RenewTicketIfOld(oldTicket);
if (ticket == null)
return;
}
string userData = ticket.UserData;
string[] roles = userData.Split(',');
HttpContext.Current.User = new GenericPrincipal(new FormsIdentity(ticket), roles);
if (ticket != oldTicket)
{
// update the cookie since we've refreshed the ticket
string cookieValue = FormsAuthentication.Encrypt(ticket);
var cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName] ??
new HttpCookie(FormsAuthentication.FormsCookieName, cookieValue) { Path = ticket.CookiePath };
if (ticket.IsPersistent)
cookie.Expires = ticket.Expiration;
cookie.Value = cookieValue;
cookie.Secure = true;
cookie.SameSite = SameSiteMode.Lax;
cookie.HttpOnly = true;
if (FormsAuthentication.CookieDomain != null)
cookie.Domain = FormsAuthentication.CookieDomain;
HttpContext.Current.Response.Cookies.Remove(cookie.Name);
HttpContext.Current.Response.Cookies.Add(cookie);
}
}
}
}
}
}
private FormsAuthenticationTicket ExtractTicketFromCookie(HttpContext context, string name)
{
FormsAuthenticationTicket ticket = null;
string encryptedTicket = null;
var cookie = context.Request.Cookies[name];
if (cookie != null)
{
encryptedTicket = cookie.Value;
}
if (!string.IsNullOrEmpty(encryptedTicket))
{
try
{
ticket = FormsAuthentication.Decrypt(encryptedTicket);
}
catch
{
context.Request.Cookies.Remove(name);
}
if (ticket != null && !ticket.Expired)
{
return ticket;
}
// if the ticket is expired then remove it
context.Request.Cookies.Remove(name);
return null;
}
return ticket;
}