我有一个单点登录解决方案,在我们的测试环境中效果很好。它使用跨子域cookie在2个Web应用程序之间共享身份验证票证。登录仅在其中一个应用程序上完成,在第二个站点上,用户将由第一个站点创建的cookie进行身份验证。
问题是,当我将其导入生产环境时,单点登录不再起作用。我正在寻找有关为什么会这样的想法。以下是更多详细信息:
1)这两个应用程序都是使用ASP.NET MVC2实现的
2)在我们的测试环境中,两个网站都位于单个服务器上,IIS中有不同的网站,并且主机标头用于服务2个Web应用程序。在生产中,站点位于地理位置不同的不同服务器上。他们使用相同的子域。
3)两个站点都具有SSL设置并可以通过https访问;这是在测试和生产中使用相同的自签名通配符证书完成的。
4)用户登录到site1,然后应用程序使用AJAX和JSONP从site2自动检索数据。
5)如果站点是site1.example.com和site2.example.com,则以下是site1和site2之间共享的web.config的重要部分:
...
<authentication mode="Forms">
<forms name=".myapp" domain=".example.com" slidingExpiration="true" loginUrl="~/Account/LogOn" timeout="30"/>
</authentication>
...
<machineKey validationKey="KEY1..." decryptionKey="KEY2..."
validation="SHA1" decryption="AES" />
...
注意:关于以上内容,我确实想知道的一件事是,身份验证票证是否经过加密/散列,从而只能在同一台服务器上解密?那可以解释我的问题;但是如果是这种情况,我如何确保site1和site2的服务器都可以解密我的身份验证Cookie? KEY1和KEY2在两个站点\服务器上都绝对相同。
6)在Site1上,用户所在的角色也可以通过以下方式插入到Cookie中:
public ActionResult LogOn(string userName, string password, bool rememberMe, string returnUrl)
{
if (!ValidateLogOn(userName, password))
{
ViewData["rememberMe"] = rememberMe;
return View(new SiteViewModel(this));
}
FormsAuth.SignIn(userName, rememberMe);
// Add roles to cookie
string[] roles = Roles.GetRolesForUser(userName);
HttpCookie cookie = FormsAuthentication.GetAuthCookie(User.Identity.Name, rememberMe);
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
// Store roles inside the Forms cookie.
FormsAuthenticationTicket newticket = new FormsAuthenticationTicket(ticket.Version, userName,
ticket.IssueDate, ticket.Expiration, ticket.IsPersistent, String.Join("|", roles), ticket.CookiePath);
cookie.Value = FormsAuthentication.Encrypt(newticket);
cookie.HttpOnly = false;
Response.Cookies.Remove(cookie.Name);
Response.AppendCookie(cookie);
if (!String.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}
return RedirectToAction("Index", "Home");
}
7)使用以下方法在Site2上还原角色:
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
if (Context.Request.IsAuthenticated)
{
FormsIdentity ident = (FormsIdentity)Context.User.Identity;
string[] arrRoles = ident.Ticket.UserData.Split(new[] { '|' });
Context.User = new System.Security.Principal.GenericPrincipal(ident, arrRoles);
}
}
编辑:
8)这是两个服务器上的应用程序引用的程序集的打印输出:
mscorlib: 2.0.0.0
System: 2.0.0.0
System.Configuration: 2.0.0.0
System.Xml: 2.0.0.0
System.ComponentModel.DataAnnotations: 3.5.0.0
System.Core: 3.5.0.0
System.Data: 2.0.0.0
System.EnterpriseServices: 2.0.0.0
System.Transactions: 2.0.0.0
System.Data.Entity: 3.5.0.0
System.Runtime.Serialization: 3.0.0.0
SMDiagnostics: 3.0.0.0
System.Web: 2.0.0.0
System.Drawing: 2.0.0.0
System.Web.RegularExpressions: 2.0.0.0
System.Web.Services: 2.0.0.0
System.Web.Abstractions: 3.5.0.0
System.Web.Extensions: 3.5.0.0
System.Data.Linq: 3.5.0.0
System.Xml.Linq: 3.5.0.0
System.ServiceModel: 3.0.0.0
System.IdentityModel: 3.0.0.0
System.ServiceModel.Web: 3.5.0.0
System.Web.Mvc: 1.0.0.0
System.Web.Routing: 3.5.0.0
xVal: 1.0.0.0
最佳答案
是。加密是特定于服务器的。或者更精确地依靠相同的机器钥匙。
尝试在两个Web配置中使用相同的机器密钥。
如果有帮助的话。删除加密,然后尝试工作
如果在完全删除安全性/加密后仍无法使用,则与不兼容的加密无关。让我们知道
更新
这是从我们的web.config中提取的。当然删除网站细节之后。尝试明确指定所有内容,尤其是路径:
<forms name=".ASPNET" protection="All" loginUrl="~/Account/LogOn" timeout="2880"
path="/" domain=".example.com"/>