使用 JSONP 實現簡單的 SSO 單點登陸

SSO 即 Single Sign On(單點登陸)。php

 1、二級域名之間的單點登陸

不須要用到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;

 

 

2、跨域的單點登陸

例若有四個項目,域名分別是 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");
}
?>
www.site2.com/p3p/login.php

 

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");
?>
www.site2.com/p3p/logout.php

 

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, '/');
        }          
    }
}
set_cookie

 

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.site2.com/p3p/index.php

 

---------------------------------------------------

圖示:

① 從 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"');
相關文章
相關標籤/搜索