**定義:**單點登錄,即SSO。是在多個應用系統中,用戶只需要登陸一次就可以訪問所有相互信任的應用系 統。
**為什么要單點登錄?**
先說一下這樣做的好處吧,先來三個屌絲域名:
www.abc.com
m.abc.com
n.abc.com
大家都知道,雖然他們都是一個域名但主機名不同,依然不能共享cookie(沒有設置到域名.openpoor.com),這就導致用戶在這些域名之間切換的時候需要重新登錄,這是不能忍受的,所以需要同步登錄。即一處登錄,處處登錄。
**案例設計:**在本地服務器測試。同一IP下,不同端口來實現不同站點之間的一次性登錄,但是相同IP下會出現session沖突,不過還好,可以通過`ini_set('session.name', 'phpsessid1');`來解決不同端口之間的session沖突問題。具體看【[解決同IP下Session沖突](288242)】。出于最簡單的案例展示,只做登錄a站點后,b站點也登錄。b站點登錄,a站點登錄,注銷這些思路一樣,不在做介紹。
**解決思路:**
假設有A站,B站。登錄A站訪問B站,B站也已經登錄。
1.在A站首頁(index.php)檢測用戶是否已經登錄。如果已經登錄,則顯示:你已經登錄首頁。如果未登錄,則返回一個A站登錄頁的(login.php)鏈接。
2.在A站登錄頁中。有個登錄表單,可以提交用戶名,密碼。根據驗證規則,檢測用戶輸入的賬號和密碼是否正確。如果驗證成功,則將A站的用戶名保存到登錄session。說明用戶已經在A站登錄。同時,頁面跳轉到A站同步登錄頁(sync.php),并且將A站用戶名通過Des加密,發送給sync.php。
3.在sync.php中,通過js請求的方式,分別請求所有要登錄的子站的同步登錄頁(slogin.php),并且將被加密的用戶名傳遞給他。請求結束后,跳回A站首頁。
4.B站的slogin.php。將獲取傳遞過來的被加密的用戶名解碼傳遞給用戶sesson。
在給B站賦值session的時候,必須遵從P3P標準。不然可能會創建session失敗。
5.訪問B站的時候,將不會再出現登錄。
**資料:P3P**是一種被稱為個人隱私安全平臺項目(the Platform for Privacy Preferences)的標準,能夠保護在線隱私權,使Internet沖浪者可以選擇在瀏覽網頁時,是否被第三方收集并利用自己的個人信息。如果一個站點不遵守P3P標準的話,那么有關它的Cookies將被自動拒絕,并且P3P還能夠自動識破多種Cookies的嵌入方式。p3p是由全球資訊聯盟網所開發的。
代碼實現:
A站index.php
~~~
<?php
session_start();
ini_set('session.name', 'phpsessid1');
// s1 為總服務臺,登錄后,子站c也登錄了
if (empty($_SESSION['username'])) {
echo "您還未登錄,<a href='/login.php'>請登錄!</a>";
}
else{
echo "您好,".$_SESSION['username']."您已經登錄了本系統。<a href='/logout.php'>注銷</a>";
}
?>
~~~
A站login.php
~~~
<?php
session_start();
?>
<form action="" method="POST" style="text-align: center;">
用戶名:<input type="text" name="username"> 密碼:<input type="text" name="password"> <input type="submit" name="submit" value="登錄">
</form>
<?php
if ($_POST['submit']) {
if ($_POST['username']=="admin" and $_POST['password']=="admin") {
// 登錄成功,通知事務
require __DIR__.'/Des.php';
$_SESSION['username'] = $_POST['username'];
$redirect = '/s1.php';
header('Location:/sync.php?redirect='.urlencode($redirect).'&code='.Des::encrypt($_POST['username'],'openpoor'));
exit;
}
}
?>
~~~
A站sync.php
~~~
<?php
// 獲取所有的數據
$redirect = empty($_GET['redirect']) ? 'http://localhost:9013' : $_GET['redirect'];
if(empty($_GET['code'])){
header('Loaction:http://'.urldecode($redirect));
exit;
}
$apps=array(
"http://localhost:9012/sync.php",
);
?>
<?php foreach ($apps as $row): ?>
<script type="text/javascript" src="<?php echo $row?>?code='.$_GET['code']";>"></script>
<?php endforeach ?>
<script type="text/javascript">
window.onload=function(){
location.replace('<?php echo $redirect; ?>');
}
</script>
~~~
B站slogin.php
~~~
<?php
session_start();
header('Content-Type:text/javascript; charset=utf-8');
if(!empty($_GET['code'])){
require __DIR__.'/Des.php';
$username = Des::decrypt($_GET['code'],'openpoor');
if(!empty($username)){
header('P3P: CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR"');
$_SESSION['username'] = $username;
}
}
echo "function _(){window.status='ok';}";//這里只是隨便返回
~~~
B站首頁 index.php
~~~
<?php
session_start();
ini_set('session.name', 'phpsessid2');
if (empty($_SESSION['username'])) {
echo "您還未登錄,<a href='/slogin.php'>請登錄!</a>";
}
else{
echo "您好,".$_SESSION['username']."您已經登錄了本系統。<a href='/logout.php'>注銷</a>";
}
~~~