本来在上一篇文章之中,就进行了Step1帐户登录系统的总结,并认为此系列已经暂时完成的,不过我闭关研究的东西并不是独立的,而是一个整体,在我把Step1账户登录系统应用到另一个项目的时候,发现有了新的想法,因此,延续上面的系列进行继续分享。
熟悉我的网友可能知道,我主要是面向客户端的JavaScript开发的,只有在不能由客户端的JavaScript完成的地方,我才考虑使用服务端,这样做一方面是因为我对客户端JavaScript的开发比较熟练,另一方面,用JavaScript确实有很多优势,例如平台无关,便于更新等,在这里我不对这个话题进行扩充。
基于以上的原因,我在将Step1帐户登录系统应用到Dituren.cn网站的时候,忽然想到,既然Step1.AccountClient反正只是简单的接收URL参数,然后读写Cookie,这两个事情用JavaScript都是可以做的,为什么不直接用JavaScript来完成呢,如果这样,会有如下优点:
1.将不再需要任何服务端的支持,就可以在页面上通过JavaScript获取到用户信息;
2.不需要服务端了,也就平台无关了,由页面自行调用Cookie来获得用户信息,加载用户信息的速度有一定的提升;
3.对于Dituren.cn这样以JavaScript为核心的网站来讲,可以做到无缝结合;
因此,我开发了一个脚本,并且将一个脚本user.js部署到Step1.AccountServer之中(既然是JS,部署到哪儿都无所谓,如果部署到AccountServer,每个Client就都可以调用同一个文件了,易于维护),这个脚本之中存在一个类K_User,提供如下功能:
1.读取Cookie之中的用户信息;并返回一个用户信息对象;
2.读取URL参数之中的回转信息,并写入到Cookie
3.转向到登录和注销的页面;
需要注意的是,我前面提供的源码之中,将数据保存到Cookie采用了Base64编码,而JavaScript不能对Base64进行解码(本来有解码的JS库,不过我不愿意因为这个去增加好多代码),因此我现在都更改为URL编码(基于UTF-8)了,这样就可以使用JavaScript的decodeURIComponent函数进行解码了。
我实现了几个简单的例子,可以试一下:
1.基础例子,在一个静态页面之中完成所有的登录相关过程;
2.静态回转代理的例子,有时候页面本身可能就有参数,这种情况下不适合再来处理回转参数,因此,可以采用另一个纯静态的文件作为回转的代理,这个代理将回转的参数保存到Cookie,然后转向到原来的页面,现在地图人网站即是采用了这种模式;
上面的例子都是纯静态的文件,代码很简单,可以很容易的看到实现的思路,也可以保存到任意网站上运行测试,只是线上调用的部署在AccountServer上的user.js文件,包含一个K_User的类,因为在线上使用,因此进行了代码压缩,其源码如下,感兴趣的可以看看:
1 function K_User(obj)
2 {
3 this.userInfo=obj?obj:{};
4 }
5 K_User.prototype.getProperty=function(key)
6 {
7 return this.userInfo[key];
8 }
9 K_User.prototype.logout=function()
10 {
11 K_User.logout();
12 }
13 K_User.getLoginUrl=function()
14 {
15 return window.SAC_serverLoginUrl+"?url="+encodeURIComponent(window.SAC_clientAgentUrl?(window.SAC_clientAgentUrl+"?url="+location.href):location.href);
16 }
17 K_User.getLogoutUrl=function()
18 {
19 return window.SAC_serverLogoutUrl+"?url="+encodeURIComponent(location.href);
20 }
21 //登录
22 K_User.login=function()
23 {
24 self.location=K_User.getLoginUrl();
25 return false;
26 }
27 //注销
28 K_User.logout=function()
29 {
30 var exp = new Date();
31 exp.setTime(exp.getTime() - 1);
32 document.cookie = window.SAC_cookieName + "=0; expires="+ exp.toGMTString()+"; path=/; domain="+(window.SAC_domain?window.SAC_domain:location.hostname);
33 self.location=K_User.getLogoutUrl();
34 return false;
35 }
36 K_User.getDefault=function()
37 {
38 return K_User._default;
39 }
40 //从Cookie之中读取
41 K_User.getFromCookie=function()
42 {
43 var reg=new RegExp(window.SAC_cookieName+"[\\s]*=([^;$]+)");
44 if(document.cookie)
45 {
46 var result=reg.exec(document.cookie);
47 if(result && result[1])
48 {
49 var obj={},items=decodeURIComponent(result[1]).split("&");
50 for(var i=0;i<items.length;i++)
51 {
52 var item=items[i].split("=",2);
53 if(item.length!=2){continue;}
54 var name=decodeURIComponent(item[0]);
55 var value=decodeURIComponent(item[1]);
56 if(name && value){obj[name]=value;}
57 }
58 return new K_User(obj);
59 }
60 }
61 return null;
62 }
63 //写入到Cookie
64 K_User.setToCookie=function()
65 {
66 var query=location.search;
67 var result=new RegExp(window.SAC_serverParamName+"=([^&$]+)").exec(query);
68 if(result && result[1])
69 {
70 userInfo=decodeURIComponent(result[1]).split(";");
71 if(userInfo.length==2)
72 {
73 var keys=userInfo[0].split(",");
74 var values=userInfo[1].split(",");
75 if(keys.length=values.length)
76 {
77 var cookieArr=[];
78 for(var i=0;i<keys.length;i++)
79 {
80 cookieArr.push(keys[i]+"="+values[i]);
81 }
82 var expireTime=new Date();
83 expireTime.setFullYear(expireTime.getFullYear()+1);
84 document.cookie =window.SAC_cookieName+ "=" + encodeURIComponent (cookieArr.join("&"))+"; expires="+expireTime.toGMTString()+"; path=/; domain="+(window.SAC_domain?window.SAC_domain:location.hostname);
85 }
86 }
87 result=new RegExp("url=([^&$]+)").exec(query);
88 self.location=(result && result[1])?result[1]:location.href.substring(0,location.href.indexOf("?"));
89 }
90 }
91 //根据Cookie的值初始化
92 K_User.init=function()
93 {
94 if(location.search && location.search.indexOf(window.SAC_serverParamName+"=")>=0)
95 {
96 K_User.setToCookie();
97 }
98 K_User._default=K_User.getFromCookie();
99 }
上面的代码也是我对此系统代码进行公开的一部分,我需要专门说明的同样是安全问题,考虑到本站对安全的要求不高(本站没有保存用户信息,用户登录只是记录用户的操作习惯),所以此登录系统也没有做任何安全方面的验证,不过并不意味着采用JS的形式就会无法对安全进行处理,因为你完全可以在登录系统之中回传参数的时候,附加一个MD5验证串,虽然JS无法对此串进行验证,在JS向服务器请求数据或者保存数据的时候,可以附加上这个验证串,服务端即可检查此验证串是不是合法,从这个角度来看,这种纯客户端的用户系统也是安全的。
这样就完成了一个纯静态的Step1.AccountClient模式,目前此模式在Dituren.cn上已经运行正常。暂时,我应该不会再对Step1账户登录系统进行研究了。