IIS 中使用 OWIN 的 MVC parent/child 站点未传递身份

MVC parent/child sites in IIS using OWIN is not passing identity

我需要在 IIS 中将一个站点嵌套在另一个站点之下,这样用户就可以在两个站点之间来回切换而无需同时登录。我之前通过 MVC 站点成功地完成了此操作,删除了子项的大部分 web.config,因此它继承了父项 web.config 并在父项配置中手动设置了机器密钥。

在parent中我手动设置了machine key并验证了child正在捡起来

我已经使用个人用户帐户(身份)测试了两个 MVC 5 网络应用程序。我使用相同的应用程序池将第二个应用程序设置为主应用程序下的虚拟应用程序。股票 MVC 应用程序工作正常。我登录到父级,导航到子级并获取身份。我可以验证,因为它在父站点和子站点中都显示 'welcome bdamore@xxxxxx.com'。

但是普通应用使用的是普通 login/ApplicationUserManager/ApplicationSignInManager 方法,而我们的父应用有很多自定义的 OWIN。

股票 MVC 站点的登录方法使用的地方:"SignInManager.PasswordSignInAsync(...)"

我们的父站点正在使用: "HttpContext.GetOwinContext().Authentication.SignIn(...)"

父站点仍在 _loginPartial.cshtml 中使用:"@User.Identity.GetUserName()",就像大多数 MVC5 子站点一样,但子站点 从不 从父级获取 Identity.User 或任何用户声明,就像股票 MVC5 parent/child 网站那样。

这是一些登录信息:

var hash = _cryptographyService.HashPassword(model.Password);
        var token = _profileService.Login(model.Email, hash);
        if (token != null)
        {
            var userData = SerializeCustomUser(token);
            var identity = new ClaimsIdentity(DefaultAuthenticationTypes.ApplicationCookie);
            identity.AddClaims(new List<Claim>
            {
              new Claim(ClaimTypes.NameIdentifier,model.Email),
              new Claim(ClaimTypes.Name,model.Email),
              new Claim("UserId", token.UserId.ToString()),
              new Claim("RoleId", token.Role.ToString()),
              new Claim("SchoolId", token.SchoolId.ToString()),
              new Claim("CampusId", token.CampusId.ToString())
            });

            if (model.RememberMe)
            {
                Response.Cookies["UserName"].Expires = DateTime.Now.AddDays(30);
            }
            else
            {
                Response.Cookies["UserName"].Expires = DateTime.Now.AddDays(-1);

            }
            Response.Cookies["UserName"].Value = model.Email.Trim();

            HttpContext.GetOwinContext().Authentication.SignIn(identity);
....

_ProfileService.Login 转到 Db 并验证信用

这里是 Startup.Auth.cs:

public void ConfigureAuth(IAppBuilder app)
    {
        // Enable the application to use a cookie to store information for the signed in user
        // and to use a cookie to temporarily store information about a user logging in with a third party login provider
        // Configure the sign in cookie
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),
            CookieName="VerityAuthSession",
            Provider = new CookieAuthenticationProvider {
              OnValidateIdentity = context =>
              {
                var url = System.Web.HttpContext.Current?.Request.Url.ToString().ToLower();
                if (url?.IndexOf("signalr") != -1 || url?.IndexOf("TwilioInfo/GetInboundCallDetails".ToLower()) != -1 || url?.IndexOf("CreateLogOffEvent".ToLower()) !=-1)
                {
                  if(url?.IndexOf("signalr") != -1)
                  {
                    var cookie = new System.Web.HttpCookie("tmpsession", context?.Identity?.Claims?.FirstOrDefault(x => x.Type == "UserId")?.Value);
                    cookie.Expires = DateTime.Now.AddSeconds(10);
                    System.Web.HttpContext.Current?.Response.Cookies.Add(cookie);
                  }
                  context.RejectIdentity();
                  return Task.FromResult<int>(0);
                }
                DateTimeOffset now = DateTimeOffset.UtcNow;

                context.OwinContext.Request.Set<double>("time.Remaining",
                       context.Properties.ExpiresUtc.Value.Subtract(now).TotalSeconds);
                System.Web.HttpContext.Current?.Response.Cookies.Add(new System.Web.HttpCookie("lastaccess", DateTime.UtcNow.ToString("MM.dd.yyyy.HH.mm.ss")));
                return Task.FromResult<object>(null);
              },
              OnException = context => {},
              OnResponseSignIn = context =>
              {
                context.Properties.AllowRefresh = true;
                context.Properties.ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(double.Parse(System.Configuration.ConfigurationManager.AppSettings[EnvironmentConsts.SessiontTimeout] ?? "45"));
              }
            }
        });
        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

        // Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
        app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));

        // Enables the application to remember the second login verification factor such as phone or email.
        // Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.
        // This is similar to the RememberMe option when you log in.
        app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);

        var signalRConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings[EnvironmentConsts.SignaRDbConnectionName].ConnectionString;
        GlobalHost.DependencyResolver.UseSqlServer(signalRConnectionString); //for using SignalR with loadbalancer we need this configuration
        app.MapSignalR();
    }

当我们的站点 ajax 转到 twillio 时,启动程序中有一些代码要处理,因此它不会像导航一样延长他们的会话。

我找到了答案。

  1. 我需要复制整个自定义的 app.UseCookieAuthentication(... 部分放入 StartupAuth.cs 文件。 parent 正在为 cookie 提供 'Name' 属性 和 apparently,它在两个应用程序中需要相同的名称。

  2. 以下需要在我们自定义设置的 OnApplicationStarted() 方法中:AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;

我们的架构师通过让我们的 global.asax.cs 继承 App_Startup 文件夹中名为“ParentApplication.cs”的文件来为 Ninject 设置它。在那里,ParentApplication.cs 文件继承自 NinjectHttpApplication.

在这个文件中有一个方法:

protected override void OnApplicationStarted()

希望这对其他人有帮助。