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

     

  • 相关阅读:
    BISDN上收集到的SAP BI的极好文章的链接
    如何设置'REUSE_ALV_GRID_DISPLAY'的单个单元格的颜色
    如何设置REUSE_ALV_GRID_DISPLAY'的单个单元格的是否可以输入
    BWABAP to copy aggregates from one cube to another
    SDva01的屏幕增强
    js鼠标悬停效果
    MySQL更新UPDATA的使用
    使用mysql C语言API编写程序—MYSQL数据库查询操作
    MySQL的部分基础语句
    MySQLdelete某个元组||、&&操作
  • 原文地址:https://www.cnblogs.com/dee0912/p/5506070.html
Copyright © 2020-2023  润新知