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

 

 

posted @ 2016-05-18 17:57  nemo20  阅读(3629)  评论(1编辑  收藏  举报
访客数:AmazingCounters.com
2016/05/17 起统计