badapple0412 发表于 2018-6-20 21:50:01

求助CI框架下的单点登陆实现

研究了好多天了,网上参考了很多资料,做了一些demo,还是不能真正的实现,求谁又经验的给予帮助,回帖讨论,或者加QQ交流

52lin 发表于 2018-6-21 08:59:54

本帖最后由 52lin 于 2018-6-21 09:30 编辑

假如域名为abc.com
登录入口统一为login.abc.com登录,登录成功后,设置一个登录cookie就好了,作用域为.abc.com
这样*.abc.com各域名下都是登录状态

如果还有其他域名也要同步登录,如域名为def.com,那么在login.abc.com登录成功的提示页面多加个<script src="http://api.def.com/sync/login?u={uid}&t={timestamp}&sign={sign}"></script>

这个script的src呢,作用主要就是生成def.com域名下的登录cookie,让def.com域名实现与abc.com同步登录,当然上面的script也可以换成iframe。

如果login.abc.com页面是ajax登录,那么上面的script的src可以在login.abc.com登录成功后的逻辑里使用CURL请求同步登录def.com

另外:u={uid}&t={timestamp}&s={sign}
{uid}为已经成功登录abc.com站点的用户id
{timestamp}为已经成功登录abc.com站点时的时间戳
{sign}为请求 s 参数之外的其他参数的加密串,加密方式你可以根据自己喜好(比如:MD5({uid}.{timestamp}.{KEY}),{KEY}为一个共同的秘钥,或者使用openssl_encrypt)


sync/login:首先要通过获取到的sign验证数据是否合法(还可以验证站点来源域名,ip等,如果需要的话)
验证通过后,也就写个def.com域名下的登录cookie就可以了

也许还有其他方法,有请楼下跟帖{:1_1:}

badapple0412 发表于 2018-6-21 11:08:43

52lin 发表于 2018-6-21 08:59
假如域名为abc.com
登录入口统一为login.abc.com登录,登录成功后,设置一个登录cookie就好了,作用域为.ab ...

谢谢,这个方式,虽然我还没有实践,但是看你说明的逻辑,针对用户主动登陆/退出(用户点击登陆或者点击退出)应该是没有问题的,我有一个疑问:如何处理登陆后的状态实时同步?   

我举个例子来说明问题:

1. 该系统需要自动退出机制——用户10分钟没有任何操作就自动退出登陆(这是很常见的做法)
2. 用户通过login.abc.com已经登陆,这时abc.com 和def.com都是登陆状态了,也记录了登陆时间。
3. 用户在def.com上面操作了5分钟时间后停止操作,并且离开了7分钟。
4. 用户回到电脑前,直接开始在abc.com上面操作。

那么问题是:
用户在第3步的时候,def.com记录的是用户已经停止7分钟没有操作了,此时还在登陆状态。
用户在第4步的时候,abc.com记录的应该是用户已经停止12分钟没有操作,按照10分钟自动退出的规则已经变成退出状态。

这两个域直接的状态如何保持同步呢?

52lin 发表于 2018-6-22 08:41:47

badapple0412 发表于 2018-6-21 11:08
谢谢,这个方式,虽然我还没有实践,但是看你说明的逻辑,针对用户主动登陆/退出(用户点击登陆或者点击 ...

如果不是硬性要求的话,每个站点都设置cookie有效期为10分钟就好了。
如果要求每个站点都共同受限于这个10分钟的话,可以缓存下来
(可以使用文件缓存,memcache等等,或者存数据库),登录站点,
登录成功后,更新该用户的自动登出的时间为当前时间+10分钟,
并设置各站点的登录cookie为关闭浏览器失效。
各个站点判断是否登录的逻辑里,如果还是登录状态,
并且在自动登出的时间范围内,则更新该用户的自动登出的时间为当前时间+10分钟,反之跳转到登录页。

这样应该能够达到你的要求

zhaohua0317 发表于 2018-6-22 11:17:24

给你贴点代码,自己研究下服务器端代码,位置在 index.php/welcome/uon

public function uon(){
    $fltime=30;//接受AJAX时间:1分钟
    $kicktime=70;//转移页面1.5分钟认为不在线
   // read_file($file);
    $lasttime =file_get_contents('./userfiles/time.dat');//上次时间
    $now=time();
    $bonline=isset($_SESSION['id']);
if ($lasttime+$fltime<$now)
{//uarr:key:IP,lastactive
    $onlineuarr = file_get_contents('./userfiles/user.dat');
    if (($onlineuarr=='')&&!$bonline)
{
      //echo json_encode(array('c'=>0));//0无在线无登陆
exit;
}
    if ($onlineuarr)
{
    $onlineuarr=unserialize($onlineuarr);
}
$oldarr=$onlineuarr;
if ($bonline)//如果是登陆状态,则先进行更新active时间
{
    $uid=$_SESSION['id'];
    $ip=$this->input->ip_address();
   if (!isset($onlineuarr[$uid]))
{
    $onlineuarr[$uid]=array($ip,$now);
}else {
    if ($ip==$onlineuarr[$uid])
{
    $onlineuarr[$uid]=$now;
}else{
    $this->ion_auth->logout();
echo json_encode(array('ip'=>$onlineuarr[$uid]));//1相同账号已经登录,被迫下线
exit;
}
}

}

if ($onlineuarr)
{
      foreach ($onlineuarr as $uid => $v) {//清理列表
      if ($v+$kicktime<$now)//如果不动作时间>600S
{
unset($onlineuarr[$uid]);//剔除
}
}
}

$this->input->set_cookie('ajaxtime',$now,0);//写入COOKIE 供客户端调用
file_put_contents('./userfiles/time.dat', $now,LOCK_EX);//写入时间文件
if ($onlineuarr)
{

if ($oldarr!=$onlineuarr)
{
    file_put_contents('./userfiles/user.dat', serialize($onlineuarr),LOCK_EX);//写入USER文件
}

}else file_put_contents('./userfiles/user.dat', '',LOCK_EX);//写入USER文件

}
}




客户端页面导入JS文件,内容为:

//读取COOKIE
function getCookie(name){
var strCookie=document.cookie;
var arrCookie=strCookie.split("; ");
for(var i=0;i<arrCookie.length;i++){
var arr=arrCookie.split("=");
if(arr==name)return arr;
}
return "";
}
/**
* flush
*/
function uon() {
      var spacet=30;//间隔时间

    var url=_ServerValue.path.base_url+'index.php/welcome/uon';
    var lastime=getCookie('ajaxtime');
if (lastime=="") {

   $.get(url, {}, function (data){
   if (data!=null) {
KS.showTips('你的账号已经在IP:'+data.ip+'处登录,您被迫下线,如有疑问请联系管理员',1,4);
setTimeout("window.location.reload()", 4000);
}
            },'json');

}else{
   if (parseInt(lastime)+spacet<_ServerValue.time) {

   $.get(url, {}, function (data){

if (data!=null) {
KS.showTips('你的账号已经在IP:'+data.ip+'处登录,您被迫下线,如有疑问请联系管理员',1,5);
setTimeout("window.location.reload()", 5000);
}
            },'json');
}
}
    setTimeout("uon()",30000);

}
jQuery(function($){
uon();
});



代码应该能看懂,懒得说了.
页: [1]
查看完整版本: 求助CI框架下的单点登陆实现