說到單點登陸你們都很瞭解,一個站點登陸其餘域會自動登陸。javascript
單點登陸SSO(Single Sign On)的方法有不少,好比:p3p、共享session、共享cookice、第三方OAuth認證。php
這裏模擬淘寶、天貓登陸。是模擬噢,要作到安全就要進行不少安全驗證RSA加密了,帶簽名的參數了等。html
淘寶與天貓登陸時都是在淘寶登陸,登陸後redirect跳轉到各自的網站HTTP_REFERER。java
本地模擬,MY淘寶:http://my-taobao.com:8080/ My天貓:http://my-tmall.com/node
爲何本地模擬的時候要修改一個的默認端口80爲8080或其餘端口,參考:http://www.cnblogs.com/dcb3688/p/4608003.htmljquery
My淘寶有三個文件,分別是:index.php login.php 與api.phpjson
index.phpapi
<?php session_start(); $session_name= isset($_SESSION['name'])?$_SESSION['name']:''; $session_token= isset($_SESSION['token'])?$_SESSION['token']:''; if($session_name){ echo "<strong>{$session_name}</strong>您已登陸My-Taobao.com <a href='/api.php?action=logout&token={$session_token}'>退出</a>"; }else{ echo "您還未登陸My-Taobao.com <a href='/login.php'>登陸</a>"; }
login.php瀏覽器
<meta charset="utf-8"/>
<form action="api.php" method="post">
<input type="text" name="name">
<input type="hidden" name="action" value="login">
<input type="hidden" name="redirect" value="<?php echo $_SERVER['HTTP_REFERER'] ?>">
<input type="submit">
</form>
<?php session_start(); $session = isset($_SESSION['token']) ? $_SESSION['token'] : ''; $redirect = isset($_REQUEST['redirect']) ? $_REQUEST['redirect'] : "/"; $action = isset($_POST['action']) ? $_POST['action'] : ''; /** * post 登陸 */ if ($action == 'login') { if ($session) { #已是登陸的狀態 echo '<meta charset="UTF-8"><script type="text/javascript">window.location.href = "' . $redirect . '";</script>'; } $session = md5(time() . uniqid()); $_SESSION['token'] = $session; $_SESSION['name'] = $_POST['name']; $_SESSION['create_time'] = time(); if (!is_dir('session')) { mkdir('session'); } $fopen = fopen('session/' . $_SESSION['token'], 'w+'); //新建文件命令 fputs($fopen, serialize($_SESSION)); //向文件中寫入內容; fclose($fopen); exit('<meta charset="UTF-8"><script type="text/javascript">window.location.href = "' . $redirect . '";</script>'); } /** * curl登陸驗證 */ if ($action == 'curl_valid') { $token = isset($_POST['token']) ? $_POST['token'] : ''; $res = 0; if ($token) { if (file_exists('session/' . $token)) { # 存在該文件 $data = unserialize(file_get_contents('session/' . $token)); if (isset($data['create_time'])) { if ($data['create_time'] > time() - 7200) { $res = 1; } } } } exit( json_encode(["status"=>$res])); } /** * get 退出 */ $actionLogout = isset($_GET['action']) ? $_GET['action'] : ''; if ($actionLogout == 'logout') { if (isset($_GET['token'])) { unlink("session/".$_SESSION['token']); unset($_SESSION['token']); unset($_SESSION['name']); } exit('<script type="text/javascript">window.location.href = "' . $_SERVER['HTTP_REFERER'] . '";</script>'); } /** * jsonp 訪問 */ $jsonp = isset($_GET['jsonp_callback']) ? $_GET['jsonp_callback'] : ''; if ($jsonp) { $status = 0; $node = []; $msg = ''; if (isset($_SESSION['token'])) { $status = 1; $msg = 'success'; $node = $_SESSION; } else { $msg = 'fail'; } exit($jsonp . '(' . json_encode(['status' => $status, 'msg' => $msg, 'node' => $node]) . ')'); }
My天貓有兩個文件: index.php 與 list.php安全
index.php
<span id="line"> </span> <script src="http://yiiui.com/static/v1/JUI/js/jquery-1.7.2.min.js"></script> <script > /** * 獲取cookie */ function getCookie(cookiename) { var result; var mycookie = document.cookie; var start2 = mycookie.indexOf(cookiename + "="); if (start2 > -1) { start = mycookie.indexOf("=", start2) + 1; var end = mycookie.indexOf(";", start); if (end == -1) { end = mycookie.length; } result = unescape(mycookie.substring(start, end)); } return result; } /** * 設置cookie */ function setCookie(name, value) { var Days = 30; var exp = new Date(); exp.setTime(exp.getTime() + Days * 24 * 60 * 60 * 1000); document.cookie = name + "=" + escape(value) + ";expires=" + exp.toGMTString(); } var token = getCookie("token"); if (token === null) { // 首次訪問my-tmall.com // php curl 不能獲取session由於curl是服務器端請求,jsonp是本地的客戶端請求。 $.getJSON("http://my-taobao.com:8080/api.php?jsonp_callback=?", function (data) { if (data.status == 1) { data = data.node; setCookie('token', data.token); console.log(data); $("#line").html("<strong>" + data.name + "</strong>您已登陸My-Tmall.com <a href='http://my-taobao.com:8080/api.php?action=logout&token=" + data.token + "'>退出 </a> <a href='list.php'>列表</a>"); } else { $("#line").html("您還未登陸My-Tmall.com <a href='http://my-taobao.com:8080/login.php'>登陸</a>"); } }); } else { // 已經登陸過,查詢如今登陸狀態 $.getJSON("http://my-taobao.com:8080/api.php?jsonp_callback=?", function (data) { if (data.status == 1) { // 登陸 data = data.node; if (data.token != token) { // 登錄其餘帳戶了 setCookie('token', data.token); window.location.href = document.location.href; } else { $("#line").html("<strong>" + data.name + "</strong>您已登陸My-Tmall.com <a href='http://my-taobao.com:8080/api.php?action=logout&token=" + data.token + "'>退出</a> <a href='list.php'>列表</a>"); } } else { // 未登陸 $("#line").html("您還未登陸My-Tmall.com <a href='http://my-taobao.com:8080/login.php'>登陸</a>"); } }); } </script>
list.php
<?php $token = isset($_COOKIE["token"]) ? $_COOKIE["token"] : ''; //print_r($token); $curl = curl(["action" => 'curl_valid', "token" => $token], "http://my-taobao.com:8080/api.php"); $ac = json_decode($curl, TRUE); if (isset($ac['status']) && $ac['status'] == 1) { # 登陸中 echo '<ul>' . '<li>1111</li>' . '<li>2222</li>' . '<li>3333</li>' . '<li>4444</li>' . '<li>5555</li>' . '</ul>'; } else { echo '已退出'; } function curl($data, $url, $method = 'POST', $headers = array()) { $ch = curl_init(); $method_upper = strtoupper($method); if ($method_upper == 'POST') { curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); } else { $url = $url . (strpos($url, '?') ? '&' : '?') . (is_array($data) ? http_build_query($data) : $data); curl_setopt($ch, CURLOPT_URL, $url); } curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method_upper); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($ch, CURLOPT_AUTOREFERER, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 30); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //SSL 報錯時使用 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); //SSL 報錯時使用 if ($headers) { curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); } $tmpInfo = curl_exec($ch); if (curl_errno($ch)) { exit(curl_error($ch)); } curl_close($ch); return $tmpInfo; }
很簡單的原理,My淘寶是正常網站登陸與註銷(主站)。當任何一個網站登陸且訪問My天貓,My天貓就Jsonp請求當前瀏覽器中是否登陸過MY淘寶。若是登陸過就種下一個cookice保存MY淘寶sessionKey。
當要訪問My天貓其餘頁面的時候可直接經過獲取Cookice使用php的CURL請求網站MY淘寶是否登陸。