SSO 即 Single Sign On(單點登陸)。php
不須要用到JSONP 或者 p3p 協議,直接使用 COOKIE 就好了,由於頂級域名相同就能實現 COOKIE 共享。html
例若有兩個項目,域名分別是 www.site1.com 和 mall.site1.com,分別對應的項目目錄是 /site1/p3p 和 /site1_originweb
site1 的登錄頁面 /site1/p3p/login.php跨域
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>site1-login</title> </head> <?php header('content-type:text/html;charset=utf-8'); session_start(); $user = isset($_SESSION['username']) ? $_SESSION['username'] : '遊客'; echo '你好, '.$user; if($user != '遊客') { echo ' | <a href="logout.php">退出</a><br /><br />'; } else { echo '<br /><br />'; } ?> <body> <form action="" method="post"> <table> <tr> <td>登陸名:</td> <td><input type="input" name="username"></td> </tr> <tr> <td>密碼:</td> <td><input type="password" name="password"></td> </tr> <tr> <td colspan="2"><input type="submit" value="登錄"></td> </tr> </table> </form> </body> </html> <?php if(isset($_POST['username'])) { $username = htmlentities($_POST['username']); $password = md5(htmlentities($_POST['password'])); // 設置同域 COOKIE setcookie('username', $username, time() + 3600, '/', 'site1.com'); $_SESSION['username'] = $username; ?> <script>window.location = "index.php";</script> <?php } ?>
經過 setcookie() 的第五個參數來設置 COOKIE 域,當設置爲 'site1.com' 時,在 www.site1.com 和 mall.site1.com 中同時會生成 COOKIE。cookie
mall.site1.com 的 index.php 頁面用於查看 COOKIE:session
<?php header('content-type:text/html;charset=utf-8'); session_start(); if(isset($_COOKIE['username'])) { $user = $_COOKIE['username']; $_SESSION['username'] = $user; } else { $user = '遊客'; } echo '你好, '.$user;
例若有四個項目,域名分別是 www.site1.com 、mall.site1.com、www.site2.com、www.sso.com,分別對應的項目目錄是 /site1/p3p 、 /site1_origin、/site2/p3p、/ssoide
如圖:post
www.site1.com 和 www.site2.com 是兩個不一樣的域,mall.site1.com 是 site1.com 的一個二級域名,www.sso.com 是處理 sso 單點登陸單獨設置的一個服務。url
原理是當用戶在 www.site1.com 或 www.site2.com 進行登錄或者註銷時,生成相應的參數,而且重定向到 www.sso.com 對全部相關的站點藉助 <script> 發送 HTTP 請求,添加或者刪除 COOKIE,以達到同時登錄同時註銷的目的,再跳轉回原站點。spa
site1 的登陸頁面 /site1/p3p/login.php:
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>site1-login</title> </head> <?php header('content-type:text/html;charset=utf-8'); session_start(); $user = isset($_SESSION['username']) ? $_SESSION['username'] : '遊客'; $welcome = $user == '遊客' ? $user : '<a href="index.php">'.$user.'</a>'; echo '你好, '.$welcome; if($user != '遊客') { echo ' | <a href="logout.php">退出</a><br /><br />'; } else { echo '<br /><br />'; } ?> <body> <form action="" method="post"> <table> <tr> <td>登陸名:</td> <td><input type="input" name="username"></td> </tr> <tr> <td>密碼:</td> <td><input type="password" name="password"></td> </tr> <tr> <td colspan="2"><input type="submit" value="登錄"></td> </tr> </table> </form> </body> </html> <?php if(isset($_POST['username'])) { $username = htmlentities($_POST['username']); $password = md5(htmlentities($_POST['password'])); // 設置同域 COOKIE setcookie('username', $username, time() + 3600, '/', 'site1.com'); $_SESSION['username'] = $username; $salt = 'sso_example_'.strtotime(date('Y-m-d H')); $token = md5($salt); // 跳轉 header("Location:http://www.sso.com/set_cookie.php?username=$username&token=$token&from=".urlencode('http://'.$_SERVER['SERVER_NAME'])."&operate=1"); } ?>
當 operate 爲 1 時爲登錄,爲 2 時爲註銷。
site1 的 COOKIE 處理頁面 /site1/p3p/set_cookie.php
<?php session_start(); $salt = 'sso_example_'.strtotime(date('Y-m-d H')); if($_GET['token'] == md5($salt) && isset($_GET['username']) && $_GET['username'] != '') { // 添加 SESSION if(1 == $_GET['operate']) { $username = trim(htmlentities($_GET['username'])); $_SESSION['username'] = $username; setcookie('username', $username, time() + 3600, '/', 'site1.com'); } else { // 刪除 SESSION session_unset(); session_destroy(); // 刪除 COOKIE setcookie('username', false, time() - 1, '/', 'site1.com'); if(isset($_COOKIE[session_name()])) { setcookie(session_name(), '', time() - 1, '/', 'site1.com'); } } }
site1 的註銷頁面 site1/p3p/logout.php
<?php header('content-type:text/html;charset=utf-8'); session_start(); session_unset(); session_destroy(); $salt = 'sso_example_'.strtotime(date('Y-m-d H')); $token = md5($salt); $username = $_COOKIE['username']; if(isset($_COOKIE[session_name()])) { setcookie(session_name(), '', time() - 1, '/', 'site1.com'); } setcookie('username', false, time() - 1, '/', 'site1.com'); echo '退出成功'; // 跳轉 header("Location:http://www.sso.com/set_cookie.php?username=$username&token=$token&from=".urlencode('http://'.$_SERVER['SERVER_NAME'])."&operate=2"); ?>
site1 的主頁,用於顯示用戶的登錄狀況 /site1/p3p/index.php
<?php header('content-type:text/html;charset=utf-8'); session_start(); if(isset($_COOKIE['username'])) { $user = $_COOKIE['username']; $_SESSION['username'] = $user; } else { $user = '遊客'; } echo '你好, '.$user; if($user != '遊客') { echo ' | <a href="login.php">返回登陸頁</a>'; echo ' | <a href="logout.php">退出</a>'; } else { echo ' | <a href="login.php">登錄</a>'; }
mll.site1.com 的主頁,查看用戶登陸或者註銷狀況 /site1_origin/index.php
<?php header('content-type:text/html;charset=utf-8'); session_start(); if(isset($_COOKIE['username'])) { $user = $_COOKIE['username']; $_SESSION['username'] = $user; } else { $user = '遊客'; } echo '你好, '.$user;
-------------------------------------------------------------------------------------
www.sso.com 藉助 script 標籤對全部站點發出 HTTP 請求。/sso/set_cookie.php
<?php $username = trim(htmlentities($_GET['username'])); $token = $_GET['token']; $from = $_GET['from']; $operate = $_GET['operate']; // 同時登錄、註銷的站點 $web_sites = array('www.site1.com', 'www.site2.com'); foreach($web_sites as $sites) { ?> <script src="http://<?php echo $sites;?>/p3p/set_cookie.php?username=<?php echo $username;?>&token=<?php echo $token;?>&from=<?php echo urlencode($from);?>&operate=<?php echo $operate;?>"></script> <?php } $from = urldecode($from); ?> <script> window.location = "<?php echo $from;?>/p3p/<?php if(1 == $operate) { echo 'index.php';}else { echo 'login.php';} ?>"; </script>
----------------------------------------------------------------------------------
site2 登錄頁面 /site2/p3p/login.php
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>site2-login</title> </head> <?php header('content-type:text/html;charset=utf-8'); session_start(); $user = isset($_SESSION['username']) ? $_SESSION['username'] : '遊客'; $welcome = $user == '遊客' ? $user : '<a href="index.php">'.$user.'</a>'; echo '你好, '.$welcome; if($user != '遊客') { echo ' | <a href="logout.php">退出</a><br /><br />'; } else { echo '<br /><br />'; } ?> <body> <form action="" method="post"> <table> <tr> <td>登陸名:</td> <td><input type="input" name="username"></td> </tr> <tr> <td>密碼:</td> <td><input type="password" name="password"></td> </tr> <tr> <td colspan="2"><input type="submit" value="登錄"></td> </tr> </table> </form> </body> </html> <?php if(isset($_POST['username'])) { $username = htmlentities($_POST['username']); $password = md5(htmlentities($_POST['password'])); // 設置同域 COOKIE setcookie('username', $username, time() + 3600, '/'); $_SESSION['username'] = $username; $salt = 'sso_example_'.strtotime(date('Y-m-d H')); $token = md5($salt); // 跳轉 header("Location:http://www.sso.com/set_cookie.php?username=$username&token=$token&from=".urlencode('http://'.$_SERVER['SERVER_NAME'])."&operate=1"); } ?>
site2 註銷頁面 /site2/p3p/logout.php
<?php header('content-type:text/html;charset=utf-8'); session_start(); session_unset(); session_destroy(); $salt = 'sso_example_'.strtotime(date('Y-m-d H')); $token = md5($salt); $username = $_COOKIE['username']; if(isset($_COOKIE[session_name()])) { setcookie(session_name(), '', time() - 1, '/'); } setcookie('username', false, time() - 1, '/'); echo '退出成功'; header("Location:http://www.sso.com/set_cookie.php?username=$username&token=$token&from=".urlencode('http://'.$_SERVER['SERVER_NAME'])."&operate=2"); ?>
site2 COOKIE 處理頁面 /site2/p3p/set_cookie.php
<?php // 使用 P3P 協議種下本域名下的 Cookie header('P3P: CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR"'); session_start(); $salt = 'sso_example_'.strtotime(date('Y-m-d H')); if($_GET['token'] == md5($salt) && isset($_GET['username']) && $_GET['username'] != '') { // 添加 SESSION if(1 == $_GET['operate']) { $username = trim(htmlentities($_GET['username'])); $_SESSION['username'] = $username; setcookie('username', $username, time() + 3600, '/'); } else { // 刪除 SESSION session_unset(); session_destroy(); // 刪除 COOKIE setcookie('username', false, time() - 1, '/'); if(isset($_COOKIE[session_name()])) { setcookie(session_name(), '', time() - 1, '/'); } } }
site2 主頁 /site2/p3p/index.php
<?php header('content-type:text/html;charset=utf-8'); session_start(); $user = isset($_SESSION['username']) ? $_SESSION['username'] : '遊客'; echo '你好, '.$user; if($user != '遊客') { echo ' | <a href="logout.php">退出</a><br /><br />'; } else { echo '<br /><br />'; }
---------------------------------------------------
圖示:
① 從 www.site1.com 登錄
② 登錄後抓包:
③ 查看 mall.site1.com
④ 查看 www.site2.com
⑤ 從 www.site1.com 退出登陸:
同時查看 mall.site1.com:
和 www.site2.com
==================================
附:
P3P 協議(Platform for Privacy Preference,隱私偏好設定平臺),經過 p3p 協議也能夠實現單點登陸。
若是使用 P3P 協議實現 SSO 單點登陸,能夠在上面的代碼中進行修改:首先設置 COOKIE 再也不是各個站點的 set_cookie.php (例如:www.site1.com/p3p/set_cookie.php 或 www.site2.com/p3p/set_cookie.php),而是轉移到 www.sso.com/set_cookie.php 中進行,通過驗證以後設置全部相關站點的 COOKIE。因爲是跨域設置 COOKIE,所以,在 www.sso.com/set_cookie.php 中應該加上:
header('P3P: CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR"');