20120104211336

这不是什么新的技术,所以如果你已经知道如何实现可以忽略此博文了。

关于同步登陆的需求,大网站可能有几个子网站或者是子系统,不能设计成每次进入其他子网站就登陆一次,而应该是在子站点登陆了就可以漫游于其他子站点,当然用户帐号与密码也应当保持一致。

当需求明确后而且你对登陆这个概念有理解的话,那么你完全可以动手了。

我们通常说的登陆与登出,反应到应用上就是一种标识符(令牌),web访问方式是无状态的(至少目前是这样的),请求方请求某个页面服务器才去帮他找到页面并解析返回,而如果要给用户一个标识符,我们往往是使用session或者是cookie,更多是前者。

更多关于session的资料,wiki

正如php里面简单的一句:session_start(),已经代表此页面启动了session,不妨echo一下session_id(),这个就是服务器给你的一个标识符,如果你不关闭浏览器即使刷新页面这个标识符仍然不变。

而对于我们应用中判断用户登陆的话一般是在session的基础上去装载了我们自定义的一些信息,比如登陆验证成功后往session中装入一些数据,之后应用就判断session中是否存在这些数据并以此作为判断用户是否登陆。

$_SESSION['userid'] = 1;//简单一句就可以了

故判断用户是否登陆的问题只变成了检查session里面是否存在userid并且这个数据是否正确则可。

if( isset( $_SESSION['userid'] ) && checkUser( $_SESSION['userid'] ) )

关于登陆的理解也就到此为止,而再来看回这个同步登陆功能的话,思路应该就更加明确了,说白了就是让其他子站点也为访问者初始化session数据,而这点是如何做到的,使用javascript。

同事之前打算使用curl,如果你以为是要由某个站点帮你去登陆其他应用那么你是对概念没理解,特别是session的概念,你要让别的子站点也承认客户端当然是要让客户端发出请求,服务端给请求方生成并初始化标识符,而不能使用curl,让服务端给你去完成其他系统的登陆,如果服务端去访问其他系统的话,那个标识符并不是客户端的,而是给服务端的,所以这就是使用curl行不通的地方。

解决方案很简单就是在任何一个子系统登陆时,会输出几个js调用声明(需要同步几个系统就有几个)

<script src="http://localhost/otherApp1/login/sync/?uid=1"></script> <script src="http://localhost/otherApp2/login/sync/?uid=1"></script> 

在其他的子系统下login控制器中也增加sync的方法即可,根据传送过来的uid去进行判断并实现对客户端的session进行初始化。

关于安全,正如上面你看到的,如果我能猜到uid,我直接访问src里面的URL也是可以实现登陆了,这是很imba的BUG,为了防止这种情况出现,你可以考虑多送一些数据,特别增加一个令牌的概念。比如:

<script src="http://localhost/otherApp1/login/sync/?uid=1&token=5e965ea1645709808cdba301ecf5f687"></script>

增加了一个token的参数,这个就是令牌,你的应用就应该预先制定好这个令牌的算法(就是令牌怎样生成的),你可以有很多组合,比如paperen这里这个就是用户ID+用户名(1paperen)然后md5的,如果不告诉你是用户ID+用户名的话,你不会猜到uid为2的令牌是多少,甚至我可以加得更复杂,你可以使用一些可逆的加密进行生成令牌,最好能实现同一个用户每次都不同令牌的效果,当然paperen说的是最好不是必须,因为光是加上复杂的组合已经够那些想打主意的人头疼了。

例子改天会补上,若有兴趣paperen更推荐自己直接动手试试看