我正在为 Multi-Tenancy ASP.NET MVC 应用程序使用 OWIN 身份验证。
应用程序和身份验证位于单个应用程序中的一台服务器上,但可以通过许多域和子域访问。例如:
www.domain.com
site1.domain.com
site2.domain.com
site3.domain.com
www.differentdomain.com
site4.differentdomain.com
site5.differentdomain.com
site6.differentdomain.com
我希望允许用户登录这些域中的任何一个并让他们的身份验证 cookie 工作,而不管使用哪个域来访问应用程序。
这就是我的身份验证设置:
public void ConfigureAuthentication(IAppBuilder Application)
{
Application.CreatePerOwinContext<RepositoryManager>((x, y) => new RepositoryManager(new SiteDatabase(), x, y));
Application.UseCookieAuthentication(new CookieAuthenticationOptions
{
CookieName = "sso.domain.com",
CookieDomain = ".domain.com",
LoginPath = new PathString("/login"),
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<UserManager, User, int>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentityCallback: (manager, user) => user.GenerateClaimsAsync(manager),
getUserIdCallback: (claim) => int.Parse(claim.GetUserId()))
}
});
Application.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
}
我还在我的应用程序的根 web.config 中为我的应用程序显式设置了一个机器 key :
<configuration>
<system.web>
<machineKey decryption="AES" decryptionKey="<Redacted>" validation="<Redacted>" validationKey="<Redacted>" />
</system.web>
</configuration>
更新
当我在 domain.com 和 site1.domain.com 之间导航时,此设置按预期工作,但现在它不允许我登录到 differentdomain.com。
我了解 cookie 与单个域相关联。但是,跨多个域持久登录的最简单方法是什么?有没有办法让我从不同的域读取 cookie,解密它,然后为 differentdomain.com 重新创建一个新的 cookie?
最佳答案
由于您需要一些简单的东西,请考虑一下。在您的特定设置中,您实际上只有一个可通过多个域名访问的应用程序,您可以进行简单的“单点登录”。首先,您必须选择负责初始身份验证的单个域名。假设是 auth.domain.com
(请记住,它只是域名 - 您的所有域仍然指向单个应用程序)。然后:
domain1.com
你发现他没有登录(没有cookie)。你引导他到auth.domain.com
登录页面。 domain1.com
(通过 Referrer header ,或者您可以显式传递域)。您验证这是您的受信任域(重要),并像这样生成身份验证 token :var token = FormsAuthentication.Encrypt(
new FormsAuthenticationTicket(1, "username", DateTime.Now, DateTime.Now.AddHours(8), true, "some relevant data"));
如果您不使用表单例份验证 - 只需使用机器 key 保护一些数据:
var myTicket = new MyTicket()
{
Username = "username",
Issued = DateTime.Now,
Expires = DateTime.Now.AddHours(8),
TicketExpires = DateTime.Now.AddMinutes(1)
};
using (var ms = new MemoryStream()) {
new BinaryFormatter().Serialize(ms, myTicket);
var token = Convert.ToBase64String(MachineKey.Protect(ms.ToArray(), "auth"));
}
所以基本上你以与 asp.net 相同的方式生成你的 token 。由于您的网站都在同一个应用程序中 - 无需担心不同的机器 key 。
domain1.com
,在查询字符串中传递加密 token 。见 here例如关于这方面的安全影响。当然,我想您使用 https,否则无论如何设置(无论是否“单点登录”)都是安全的。这在某些方面类似于 asp.net“无cookie”身份验证。 domain1.com
您会看到该 token 并验证:var ticket = FormsAuthentication.Decrypt(token);
var userName = ticket.Name;
var expires = ticket.Expiration;
或与:
var unprotected = MachineKey.Unprotect(Convert.FromBase64String(token), "auth");
using (var ms = new MemoryStream(unprotected)) {
var ticket = (MyTicket) new BinaryFormatter().Deserialize(ms);
var user = ticket.Username;
}
domain1.com
上创建 cookie使用您在 token 中收到的信息并将用户重定向回他最初来自的位置。 所以有一堆重定向,但至少用户只需输入一次密码。
更新以回答您的问题。
为什么我们需要所有这些,即使我们有一个应用程序只能从不同的域访问?因为浏览器不知道这一点并且对待它们完全不同。除此之外 - http 协议(protocol)是无状态的,每个请求都与其他请求无关,因此我们的服务器还需要确认请求 A 和 B 由同一用户发出,因此需要这些 token 。
HttpServerUtility.UrlTokenEncode
在这里使用非常好,甚至比 Convert.ToBase64String
更好,因为无论如何您都需要对其进行 url 编码(您在查询字符串中传递它)。但是,如果您不会在查询字符串中传递 token (例如,您将使用上面的 javascript 方式 - 您不需要对它进行 url 编码,所以在这种情况下不要使用 HttpServerUtility.UrlTokenEncode
。关于c# - Multi-Tenancy ASP.NET MVC 应用程序的跨域 OWIN 身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36776606/