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


SSO 即 Single Sign On(單點登錄)。

 一、二級域名之間的單點登錄

不需要用到JSONP 或者 p3p 協議,直接使用 COOKIE 就行了,因為頂級域名相同就能實現 COOKIE 共享。

例如有兩個項目,域名分別是 www.site1.com 和 mall.site1.com,分別對應的項目目錄是 /site1/p3p 和 /site1_origin

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。

 

mall.site1.com 的 index.php 頁面用於查看 COOKIE:

<?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、/sso

如圖:

 

www.site1.com 和 www.site2.com 是兩個不同的域,mall.site1.com 是 site1.com 的一個二級域名,www.sso.com 是處理 sso 單點登錄單獨設置的一個服務。

原理是當用戶在 www.site1.com 或 www.site2.com 進行登陸或者注銷時,生成相應的參數,並且重定向到 www.sso.com 對所有相關的站點借助 <script> 發送 HTTP 請求,添加或者刪除 COOKIE,以達到同時登陸同時注銷的目的,再跳轉回原站點。

 

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"');

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM