.NET 4.8 Web 窗体 - IIS Express - 两个虚拟目录,一个应使用 FormsAuth,另一个应使用 WindowsAuth,但 Prinicipal 始终是 WindowsIdentity

.NET 4.8 Web Forms - IIS Express - Two Virtual Directories, One Should Use FormsAuth, Other WindowsAuth, but Prinicipal is Always WindowsIdentity

提问人:codeMonkey 提问时间:8/9/2023 更新时间:8/9/2023 访问量:62

问:

我的网站在 IIS 上工作正常,但 IIS Express 失败。

tl:博士;如何在同一域下的 IIS Express 中配置两个单独的 .NET 4.8 Framework 应用程序作为虚拟目录,但一个使用 Windows 身份验证,另一个使用 Forms 身份验证?目前,Windows 身份验证正在覆盖它们。

我有一个站点/域,有两个虚拟目录,每个目录都指向不同的应用程序:

- domain.com
  - virualDirectory1 (/app1windows)
  - virtualDirectory2 (/app2forms)

app1windowsuses ,从 Active Directory 获取用户的标识,然后创建 Cookie。然后,此应用程序重定向到 ,读取 cookie,执行一些逻辑,然后设置一个新的 cookie,其中包含仅可用的附加信息。所有这些都很好。我什至用 .WindowsAuthenticationFormsAuthentication/app2forms/handler.ashxFormsAuthenticationapp2formsHttpContext.Current.UserGenericPrincipalFormsIdentity

当尝试导航到页面并经过 . . .在这里,始终是 类型 ,尽管应为此应用程序关闭 Windows 身份验证。/app2formsApplication_AuthenticateRequestHttpContext.Current.User.IdentitySystem.Security.Principal.WindowsIdentity

在我的web.config中,它非常清楚地指出:/app2forms

<system.web>
    <authentication mode="Forms">
        <forms cookieless="UseCookies" name="cookieName" path"/" etc. />
...

我右键单击了 的项目文件并显式设置为 。/app2formsWindows AuthenticationDisabled

在 的 .CSPROJ文件我已经设置了。app2forms<IISExpressWindowsAuthentication>disabled</IISExpressWindowsAuthentication>

我已经打开了applicationhost.config文件,并为每个虚拟目录设置了唯一的s。applicationPool

我的applicationhost.config文件中没有任何地方被启用,除了显式启用。windowsAuthenticationapp1windows

我需要这些应用在其 web.config 文件中具有相同集的同一域下并发运行,否则将无法跨应用识别 cookie。machineKey

为什么/如何在任何地方看到任何类型的 WindowsIdentity?如何使一个应用识别 WindowsIdentity,而另一个应用使用 FormsIdentity?请帮忙。app2forms

C# .NET Web 窗体身份验证 IIS-Express

评论


答:

0赞 codeMonkey 8/9/2023 #1

好吧,我没有试图与之抗争,而是决定顺其自然。我通过@dean-harding找到了这个答案,它建议在检测到时抓取表单cookie。所以这是我的解决方案:WindowsIdentity

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;
}