php+ajax实现跨域单点登陆

以前咱们在《SSO单点登陆三种状况的实现方式详解》中介绍过跨域单点登陆的原理。这里向你们介绍利用php和ajax具体实现单点登陆。php

在本次示例中咱们须要两个站点:html

www.onmpw.com
www.onmpw1.comgit

固然还有一个验证系统github

www.SSOsite.comajax

为了实现单点登陆。首先,咱们须要将要设置两个站点使其共享session。至于如何共享session,能够参考《PHP集群session共享》这篇文章。这里咱们就不作详细的介绍了。json

假设咱们已经设置了两者能够共享session了。下面咱们就来介绍具体实现的流程。跨域

第一部分浏览器

下面咱们用文字来描述该过程cookie

·浏览器请求onmpw的须要验证的页面。session

·经过ajax请求SSOsite系统,查看是否存在SSOsite站点的cookie信息,若是不存在则通知浏览器须要进行登陆。

·浏览器接收到须要登陆的信息后请求onmpw的登陆页面(固然有的系统是统一使用SSOsite的登陆系统,那就须要浏览器再去请求SSOsite的登陆页面了)。

·提交登陆信息到onmpw系统。onmpw系统经过curl技术将登陆信息发送给SSOsite系统进行验证。

curl_setopt($ch, CURLOPT_URL, "www.SSOsite.com/?c=Auth&a=authUser");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, array('username'=>$username,'password'=>$password));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec($ch);
$res = json_decode($data);

·SSOsite验证成功之后,生成token,并将用户信息连同生成的token一并返回给onmpw系统。

const chars = 'abcdefgABCDEFG012hijklmnHIJKLMN3456opqrstOPQRST789UVWXYZuvwxyz';
static public function str_random(){
     //随机生成token串
     $chars = self::chars;
     $token = '';
     for($i = 0; $i < 5; $i++){
        $str = substr($chars,0,mt_rand(0, strlen($chars)-1));
        $token .= $str.$chars[mt_rand(0, strlen($str)-1)];
     }
     $token = md5($token);
     return $token;
 }

·onmpw接收到SSOsite返回的验证成功的信息之后,将用户信息写入浏览器的cookie中。最后将登陆成功的信息响应给浏览器。

setcookie('userid',$res->userid,null,'/');    //设置本站点cookie

·而后浏览器再次经过ajax将获得的token发送给SSOsite。

checkToken:function(args){
         $.ajax({
                   url:Onmpw_SSO.Configure.SSO_Server+'/?c=Auth&a=checkToken',
                   xhrFields: {withCredentials: Onmpw_SSO.Configure.Cross_Domain},
                   dataType:'json',
                   type:'post',
                   data:{token:args.token,userid:args.userid},
                   success:function(data){
                            args.Suc();
                   },
                   error:function(err){
                            console.log(err);
                   }
         })
},

SSOsite获得token之后将token存入浏览器端cookie和session中。

public function checkToken(){
      $this->authUrl();
      session_start();
      if(isset($_POST['token'])){
          setcookie('usertoken',$_POST['token'],null);
          setcookie('userid',$_POST['userid'],null);
          $_SESSION['token'] = $_POST['token'];
          echo json_encode(array('auth'=>'SUC'));
      }
 }

注意在浏览器经过ajax向SSOsite发送请求的状况下须要设置CORS(跨域资源共享)

private function authUrl(){
        $origin = $_SERVER['HTTP_ORIGIN'];
        if (in_array($origin, $this->urlArr)) {
            header("Access-Control-Allow-Origin:" . $origin);
            header("Access-Control-Allow-Credentials: true ");
        }else{
            echo "error!";
            exit;
        }
    }

设置完成之后,返回浏览器登陆成功。

第二部分

下面咱们用文字描述该过程

·浏览器请求onmpw的须要验证的页面。

·经过ajax带着cookie信息请求SSOsite系统。SSOsite系统在cookie中提取用户token。而后再次生成一个临时token存入session中,其键名为用户token。最后通知浏览器该用户已经登陆成功,而且将临时token一并返回给浏览器。

$tmptoken = \Common::str_random();
$_SESSION[$_SESSION['token']] = $tmptoken;

·浏览器接收到临时token,而后再次经过ajax将临时token发送给SSOsite进行验证。SSOsite验证完成临时token,将session中的临时token销毁。而且获得本身的sessionId返回给浏览器。

public function authToken(){
    $this->authUrl();
    session_start();
    $tmptoken = $_POST['tmptoken'];
    if($tmptoken == $_SESSION[$_SESSION['token']]){
        unset($_SESSION[$_SESSION['token']]);
        echo json_encode(array('auth'=>'SUC','userid'=>$_COOKIE['userid'],'sessionId'=>session_id()));
    }else{
        echo json_encode(array('auth'=>'FAIL'));
    }
 }

·浏览器收到SSOsite返回的sessionId之后,将sessionId发送给onmpw。onmpw系统接收到浏览器带来的sessionId之后,用此sessionId来初始化自身的session。将先前存入浏览器cookie中的用户信息存入session中而且销毁cookie信息(固然在session开启以后,咱们先检查session中是否存在用户信息,若是不存在则将cookie中的用户信息存入session,并销毁cookie)。

$sessionId = $_POST['sessionId'];
session_id($sessionId);
session_start();
if(!isset($_SESSION['userid'])){
    $userid = $_COOKIE['userid'];
    setcookie('userid',"",time()-3600,'/');
    $_SESSION['userid'] = $userid;
}

·这样浏览器就能够知道用户信息存在,进行相应的操做。在第一部分步骤完成之后,用户也能够请求onmpw1。其步骤是和第二部分描述的相同。

至此,经过php和ajax实现跨域单点登陆的流程已经所有完成。其中有一部分核心代码,能够点此查看完整代码。但愿本文对你们有所帮助。

相关文章
相关标签/搜索