实例演示单点登录SSO

好久没更博文了,刚好有点时间写点东西。

最近刚给公司的几个项目整合了单点登录功能,给很多没做过的小伙伴提供点思路,说不定啥时候就用上了是吧

什么是单点登录?

一个企业可能有多个站点,在其中某个站点登录后,访问其他站点的隐私信息的时候,不需要再次登录即可访问,避免多个项目多次登录,提升用户体验,这就是单点登录

 

做单点登录要面对哪些问题

基于web应用,我们实现客户端和服务端交互的时候常用cookie和session,后端session共享实现的方式有很多,比如redis,这比较好处理,我们也不在这里赘述。单点登录要面对的主要问题的cookie不能跨域

比如www.A.com下的cookie名为cookie_a ,在我们访问www.B.com的时候,请求头是不会携带上cookie_a的,这就是主要的问题。

我们在A系统登录过后,A站点下的cookie保存着一个token,但是访问B站点的时候,我们无法向服务端发送A站点下的token,所以还需要再次登录。

那么如果要实现单点登录,关键点在于几个站点之间,传递token

 

怎么实现单点登录

我们的大致思路是用一个统一的SSO会话管理服务器,所有业务系统的登录、退出,都由这个SSO服务器来完成。登录后生成token ,把token传递给业务系统,业务系统拿到URL中的token后,保存到cookie。

这个SSO服务器还需要有token检验的功能,这点我们后面细说,这里我用简单的代码给大家演示一下,重在思路。

比如说我们现在有两个业务系统要做单点登录,分别是会员系统 和 订单系统,域名分别是http://ucenter:991 和 http://order:992/

我们建立一台SSO服务器,域名为http://sso:994

假如我们现在没有登录,然后我们访问会员系统的个人主页:http://ucenter:991/main.php

这个时候没有回话,需要跳转去SSO服务器登录,登录页面是http://sso:994/login.php,

但实际上我们需要跳转的地址是:

http://sso:994/login.php?return_url=http%3A%2F%2Fucenter%3A991%2Fmain.php (return_url参数是我们跳转前想访问的业务系统的地址)

这里传递redirect_url参数是为了登录完成后的跳转

在我们提交用户名密码后,SSO服务器验证通过后,生成一个token名 ,形如:698d51a19d8a121ce581499d7b701668

创建一个全局会话(全局会话指的是SSO服务器下的会话),通过setCookie函数生成将token名保存在SSO域下

此时,SSO域下已经成功创建了会话。

但是我们ucenter域下还没有会话,我们在登录完成后,根据redirect_url(来源页),拼接上我们新生成的token名,进行跳转,跳转URL地址形如:

http://ucenter:991/main.php/?token=698d51a19d8a121ce581499d7b701668

ucenter系统检测到url中携带了token参数,拿到这个参数值,请求SSO服务器的token验证接口,目的是为了验证这个token是否有效,有效的话就为ucenter域生成会话,保存token到cookie中。这样,ucenter域也拥有了会话。
 

此时,用户访问第二个业务系统 http://order:992/order.php

但是这个域下没有会话,会跳去 http://sso:994/login.php?return_url=http%3A%2F%2Forder%3A992%2Forder.php%2F

但是SSO域下已经有会话了,在检测到会话信息还有效,则不会展示出登录页面,而是取出token名,跳转回业务系统:

http://order:992/order.php/?token=47bce5c74f589f4867dbd57e9ca9f808

业务系统也是一样取出URL中的token,请求SSO服务器的token验证接口,有效的话就生成该order域下的会话

这样一来,用户只需要登录一次,就可以任意访问多个业务系统,在用户体验上,用户仿佛是在一个系统中完成了登录,然后其他系统也跟着可以访问了 

实际上的流程是:

访问ucenter ->跳转到OSS登录页面->登录后生成token,跳转到ucenter系统,携带token参数->ucenter系统拿到token参数,生成会话信息->用户访问其他任何系统->发现都没会话,跳转到SSO登录->发现OSS域下有会话,拿到token,跳转回业务系统,携带token参数->业务系统拿到后,验证token有效,生成会话

这里我简单用原生PHP演示一下两个业务系统的代码,服务端会话我就用个文本来保存了,我本地没装redis

main.php

url($verifyUrl)->method("post")->data(['token'=>$token])->exec();
        if($response['data']['verifyResult']==1)
        {
            //有效,生成局部会话
            setCookie('token',$token,time()+7200);
        }
        else
        {
            //无效的token,跳转去登录页
            jumpLogin();
        }


    }
}
else
{
    //cookie中已经有了token,默认认为已经登录
    $token = $_COOKIE['token'];
}

if(file_exists("./../$token.txt"))
{
    $userInfo = unserialize(file_get_contents("./../$token.txt"));
    echo "用户信息:
"; } else { //服务端session信息不存在了 jumpLogin(); }

order.php 跟main.php 基本一样

 

login.php

'吴小佳','age'=>18];
         $token = md5($_POST['password']);
         $re = file_put_contents("./../$token.txt",serialize($userInfo));
         setCookie('token',$token,time()+7200);
         //重定向
         $url = $_GET['return_url']."/?token=".$token;
         header("Location:$url");
     }
 }
 else
 {
     //请求头中携带了token,验证token是否有效
     $token = $_COOKIE['token'];
     if(file_exists("./../$token.txt"))
     {
        //token有效,跳回来源页,并携带上token信息
         $url = $_GET['return_url']."/?token=".$token;
         header("Location:$url");
     }
 }
?>



    


    

 

verify.php (验证接口)

'吴小佳','age'=>18];
         $token = md5($_POST['password']);
         $re = file_put_contents("./../$token.txt",serialize($userInfo));
         setCookie('token',$token,time()+7200);
         //重定向
         $url = $_GET['return_url']."/?token=".$token;
         header("Location:$url");
     }
 }
 else
 {
     //请求头中携带了token,验证token是否有效
     $token = $_COOKIE['token'];
     if(file_exists("./../$token.txt"))
     {
        //token有效,跳回来源页,并携带上token信息
         $url = $_GET['return_url']."/?token=".$token;
         header("Location:$url");
     }
 }
?>



    


    

 

你可能感兴趣的:(PHP)