说到单点登录大家都很了解,一个站点登录其他域会自动登录。
单点登录SSO(Single Sign On)的方法有很多,比如:p3p、共享session、共享cookice、第三方OAuth认证。
这里模拟淘宝、天猫登录。是模拟噢,要做到安全就要进行很多安全验证RSA加密了,带签名的参数了等。
淘宝与天猫登录时都是在淘宝登录,登录后redirect跳转到各自的网站HTTP_REFERER。
本地模拟,MY淘宝:http://my-taobao.com:8080/ My天猫:http://my-tmall.com/
为什么本地模拟的时候要修改一个的默认端口80为8080或其他端口,参考:http://www.cnblogs.com/dcb3688/p/4608003.html
My淘宝有三个文件,分别是:index.php login.php 与api.php
index.php
<?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淘宝是否登录。