跨域登录
跨域登录跨域登录是一个比较烦人的事情,往往我们需要写文章记录下来,或者探讨,或者抛砖引玉的问题,都是令人头疼的。上次简单得写了一篇关于跨域登录的文章,只讲了大体的实现过程。但是现在碰到了更大的问题,这
跨域登录
跨域登录是一个比较烦人的事情,往往我们需要写文章记录下来,或者探讨,或者抛砖引玉的问题,都是令人头疼的。上次简单得写了一篇关于跨域登录的文章,只讲了大体的实现过程。但是现在碰到了更大的问题,这篇文章将会介绍这个成败,并探讨、实现新方案的可行性。
跨域登录需要一张通行证,也可以称之为票据。就老衲现在知道和实验的方式一共有三种:
1、浏览器get 参数;
2、session
3、cookie
每个都有特定的条件,以及需要处理的细节,也会带来一些新问题。根据经验,浏览器带参数,将会使系统开发得不像个东西,至少我是这么认为的。需要考虑对这个地址参数处理的各种策略,一开始我就否定了这个方案。在我需要改造的项目中有4个独立域名,跳转来跳转去,将会给用户造成极为不爽的体验。
session 也可以解决问题,但是有一个问题无法解决。
先看看怎么用session 解决问题。假设现在有a.com,b.com ,现在开两个子域名: passport.a.com 和passport.b.com 。然后把这两个域名指向同一个站点,也就是在同一个站点的http 投绑定这两个域名。
那么登录的时候,在 passport.a.com 上登录成功,就可以设置一个session ,那么在两个系统当中都是可以通过代理文件,访问到这个session 的,这个方案确实是可行的。但是session 只能保持20分钟,新问题就出来了。假设这个用户20分钟没有去操作,而打开了另外一个域名,那么这个判断就失效了。访问本域是没问题的,cookie 还在那里摆着。 我比较倾向于用cookie 来解决问题。上一次设计的系统,可以说极其简单。4个系统,有3个是asp.net 的,还有个论坛是asp 的(不用说就是动网的了)。现在就有四套登录系统。如果整体上全部改造,老衲认为成本太大了。后来四处逛网站,借鉴了Sohu 的登录方式,但是只做了个体验的实现,如果全部实现了就不会现在在这里探讨这个问题了。解决方案就是javascript iframe实现的。
本来想用纯javascript 实现,然后给src 的文件带参数,但是实际开发过程中,应该是我的js 水平太菜,所以感觉不到想要的那种效果。后来就采用了javascript iframe的方式来实现。是无刷新的那种哦,呵呵。
// JavaScript Document
//
javascript 使用很简单,点击登录也就是调用了OnSign 方法,将会向
passport.c.com/jslogin.aspx发出请求。
Response.AddHeader("P3P", @"CP=""CURaADMaDEVaPSAoPSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR""");
Response.AddHeader("Content-Encoding:", "utf-8");
string url = Request.ServerVariables["HTTP_REFERER"];
if (!string.IsNullOrEmpty(url) &&url.IndexOf('#') > 0)
{
url = url.Substring(0, url.IndexOf('#'));
,}
string username = Request["username"];
string password = Request["password"];
Response.Write("");
Response.End();
}
password = HttpUtility.UrlDecode(password, System.Text.Encoding.UTF8); password = EncryptHelper.MD5(password);
password = password.Substring(8, 16);
BBSUserbu = BBSUserHelper.Current(username, password);
if (bu.UserID != 0)
{
DateTimedt = DateTime.Now;
string save = RequestHelper.Get("save");
//dt = string.IsNullOrEmpty(save) ? dt.AddHours(2) : dt.AddMonths(1); dt = dt.AddMonths(1);
Guid g = Guid.NewGuid();
StatUserHelper.Delete(bu.UserID);
StatUsersu = new StatUser();
su.UserID = bu.UserID;
su.UserName = bu.UserName;
su.ExpireTime = dt;
su.CreateTime = DateTime.Now;
su.Guid = g;
,su.Password = bu.Password;
su.ID = StatUserHelper.Add(su);
string cachedate = su.Guid.ToString() "|" su.ID;
string cacheuser = bu.UserID "|" bu.UserName;
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, cachedate, DateTime.Now, dt, true , cacheuser);
string authTicket = FormsAuthentication.Encrypt(ticket);
HttpCookieUserCookie =
new HttpCookie(FormsAuthentication.FormsCookieName, authTicket); UserCookie.Domain = ".c.com";
UserCookie.Expires = ticket.Expiration;
if (Response.Cookies[FormsAuthentication.FormsCookieName] == null ) Response.Cookies.Add(UserCookie);
else
Response.Cookies.Set(UserCookie);
Response.Write("'" cachedate "|" HttpUtility.UrlEncode(bu.UserName, Encoding.UTF8) "';");
Response.End();
}
Response.Write("'0|';");
Response.End();
jslogin 的代码就是个验证的过程,加的P3P 头,是可以跨域写入Cookie 的保证。这里使用的是.Net 的Forms 验证,要保持和其它域名加密方式以及名称的统一。假如有两个域同时指向一个站点的话。
这里返回javascript 并且操作iframe 的父窗口,改变地址,而引用的js 会监视地址栏,发现数据,根据数据的格式,判断是否验证成功,如果成功了,那么会向各个站点下的一个SetLogin 文件发出请求,当然被请求的页面需有P3P 头。
这样在一个地方登录,实际上是同时向其它域名写入Cookie ,退出的原理也是一样的。 但是,在Maxthon 中Iframe 操作父窗口地址这个操作是不允许的,它认为这个不安全,我倒是没觉得。这个问题还不太大,毕竟有Maxthon 的用户不是太多,即使用了,告诉他不能用,他也会用IE 。
但是IE8 beat 2这种操作方式将会弹出新窗口。在IE8 beat2中使用Iframe 解决方案就会变得体验很不好。而且还给老衲带来了心灵上的伤害,以后不敢什么都写在客户端了,浏览器版本一变,对整体影响太大了。
下一个可替代方案就是使用反向代理,sohu 的无刷新登录就是基于这个实现的据说,目前还在研究中。上一次因为时间急迫,没有时间仔细实验。这次是没办法躲过去了。