zoukankan      html  css  js  c++  java
  • php单点登录SSO(Single Sign On)的解决思路

    一、什么是单点登录

    解释:登录一个系统后,其它系统无需再次登录,即可进入。

    二、举个例子:

    你登录了淘宝,然后你进入天猫,发现你不用登录了。这时你要注意到,淘宝跟天猫可是完全不一样的域名。

    你登录淘宝后,你的浏览器得到了cookie,但是这个cookie是在淘宝域名下的。你的天猫域名下并没有cookie。

    这个时候你要想办法让天猫域名下也有这个相同的cookie。假设你的天猫域名下也有这个cookie。

    当你的浏览器进入天猫时,你的浏览器会携带天猫域名下的cookie去服务器验证。

    但是这个cookie对应的可是淘宝域名下的session数据,这个时候又该如何呢。

    从这个例子中引出两个问题:

    1、跨域种cookie

    2、服务端保持cookie对应的session数据是一样的

    三、解决思路

    四、示例代码

    A域名下的 index.php 文件

    <?php
        header("Content-type: text/html; charset=utf-8");
    
        if(!empty($_POST)) {
            $response = curl_post('http://www.U.com/index.php',$_POST);
            if($response['code'] > 0) {
                die('error:'.$response['msg']);
            }
    
            set_cookie('SID',$response['data']['sid'],0,'/','',0,1);
            echo '登录成功';
            $url = 'http://www.B.com/setcookie.php?sid='.$response['data']['sid'];
            die('<script type="text/javascript" src="'.$url.'" reload="1"></script>');
    
        }
    
        function curl_post( $url , $arrPost = array() , $func = "http_build_query" ){
            $ch = curl_init();
    
            $opt[CURLOPT_URL] = $url;
            $opt[CURLOPT_RETURNTRANSFER] = 1;
            $opt[CURLOPT_TIMEOUT] = 10;
            if( !empty( $arrPost ) ){
                if( $func == 'json_encode' )
                    $opt[CURLOPT_HTTPHEADER] = array("Content-Type: application/json;charset=UTF-8");
                $opt[CURLOPT_POST] = 1;
                $opt[CURLOPT_POSTFIELDS] = call_user_func( $func , $arrPost );
            }
    
            curl_setopt_array ( $ch, $opt );
            $response = curl_exec( $ch );
            curl_close( $ch );
    
            return json_decode($response, true);
        }
        /**
         * 免刷新写入cookie
         * name     必需。规定 cookie 的名称。
         * value     必需。规定 cookie 的值。
         * expire     必需。规定 cookie 的有效期。
         * path     可选。规定 cookie 的服务器路径。
         * domain     可选。规定 cookie 的域名。
         * secure     可选。规定是否通过安全的 HTTPS 连接来传输 cookie。
         * httponly 可选。规定是否禁止js读取cookie。
         */
        function set_cookie($name,$value='',$expire=0,$path='/',$domain='',$secure=0,$httponly=0) {
            $_COOKIE[$name] = $value;
            if(is_array($value)){
                foreach($value as $k=>$v){
                    if(is_array($v)){
                        foreach($v as $a=>$b){
                            setcookie($name.'['.$k.']['.$a.']',$b,$expire,$path,$domain,$secure,$httponly);
                        }
                    }else{
                        setcookie($name.'['.$k.']',$v,$expire,$path,$domain,$secure,$httponly);
                    }
                }
            }else{
                setcookie($name,$value,$expire,$path,$domain,$secure,$httponly);
            }
        }
    ?>
    <!DOCTYPE HTML>
    <html>
        <head>
            <title>A域名的登录框</title> 
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        </head>
        <body>
            <form action="http://www.A.com/index.php" method="post">
                <input type="text" name="uname" placeholder="帐号"/>
                <input type="password" name="upasswd" placeholder="密码"/>
                <input type="submit" value="提交" />
            </form>
        </body>
    </html>

    B域名下的 index.php 文件

    <?php
    header("Content-type: text/html; charset=utf-8");
    $sid = isset($_COOKIE['SID']) ? $_COOKIE['SID'] : '';
    
    if(empty($sid)) echo "请先登录";
    
    $response = curl_post('http://www.U.com/index.php',array('sid'=>$sid));
    if($response['code'] > 0) {
        die('error:'.$response['msg']);
    }
    
    die('您的帐号密码是:'.$response['data']['uinfo']);
    
    function curl_post( $url , $arrPost = array() , $func = "http_build_query" ){
        $ch = curl_init();
    
        $opt[CURLOPT_URL] = $url;
        $opt[CURLOPT_RETURNTRANSFER] = 1;
        $opt[CURLOPT_TIMEOUT] = 10;
        if( !empty( $arrPost ) ){
            if( $func == 'json_encode' )
                $opt[CURLOPT_HTTPHEADER] = array("Content-Type: application/json;charset=UTF-8");
            $opt[CURLOPT_POST] = 1;
            $opt[CURLOPT_POSTFIELDS] = call_user_func( $func , $arrPost );
        }
    
        curl_setopt_array ( $ch, $opt );
        $response = curl_exec( $ch );
        curl_close( $ch );
    
        return json_decode($response, true);
    }

    B域名下的 setcookie.php 文件

    <?php
    header("Content-type: text/html; charset=utf-8");
    $sid = isset($_GET['sid']) ? $_GET['sid'] : '';
    
    if(!empty($sid)) {
        set_cookie('SID',$sid,0,'/','',0,1);
    }
    
    /**
     * 免刷新写入cookie
     * name     必需。规定 cookie 的名称。
     * value     必需。规定 cookie 的值。
     * expire     必需。规定 cookie 的有效期。
     * path     可选。规定 cookie 的服务器路径。
     * domain     可选。规定 cookie 的域名。
     * secure     可选。规定是否通过安全的 HTTPS 连接来传输 cookie。
     * httponly 可选。规定是否禁止js读取cookie。
     */
    function set_cookie($name,$value='',$expire=0,$path='/',$domain='',$secure=0,$httponly=0) {
        $_COOKIE[$name] = $value;
        if(is_array($value)){
            foreach($value as $k=>$v){
                if(is_array($v)){
                    foreach($v as $a=>$b){
                        setcookie($name.'['.$k.']['.$a.']',$b,$expire,$path,$domain,$secure,$httponly);
                    }
                }else{
                    setcookie($name.'['.$k.']',$v,$expire,$path,$domain,$secure,$httponly);
                }
            }
        }else{
            setcookie($name,$value,$expire,$path,$domain,$secure,$httponly);
        }
    }

    U域名下的 index.php 文件

    <?php
    header("Content-type: text/html; charset=utf-8");
    
    $sid = isset($_POST['sid']) ? $_POST['sid'] : '';
    if(!empty($sid)) {
        $uname_upasswd = file_get_contents($sid);
        if(empty($uname_upasswd)) {
            die(json_encode(array(
                'code'=>1,
                'msg'=>'fail',
                'data'=>array()
            )));
        }
        die(json_encode(array(
            'code'=>0,
            'msg'=>'success',
            'data'=>array('uinfo'=>$uname_upasswd)
        )));
    }
    
    $uname = isset($_POST['uname']) ? $_POST['uname'] : '';
    $upasswd = isset($_POST['upasswd']) ? $_POST['upasswd'] : '';
    if($uname == '' || $upasswd == '') {
        die(json_encode(array(
            'code'=>1,
            'msg'=>'fail',
            'data'=>array()
        )));
    }
    
    define('SID_SALT', '密码盐');
    
    $passwd = passwd($uname.$upasswd,SID_SALT);
    file_put_contents($passwd, $uname.','.$upasswd);
    
    die(json_encode(array(
        'code'=>0,
        'msg'=>'success',
        'data'=>array('sid'=>$passwd)
    )));
    
    
    function passwd($string,$salt) {
        return md5(substr(md5($string).md5($salt),16,48));
    }

    验证流程:

    1、进入A域名,输入帐号密码点击登录。

    2、进入B域名,此时会打印出你在A域名输入的帐号密码。

    注意:这只是一个简单的验证,实际开发中需要做cookie加密,实效验证等。而且,其实单点登录问题,还有其他解决思路。

  • 相关阅读:
    如何处理前端异常监控?
    【效果】使用canvas rotate实现一个旋转的矩形
    小tips:微信小程序登录后返回登录前的页面继续操作(保留参数)
    nginx的常用配置
    vue-router的History 模式常用的三种配置方式(去掉地址栏中的#号)
    web前端常用的五种方式搭建本地静态html页面服务器
    小tips:nodejs请求接口超时使用中间件connect-timeout实现自动超时机制
    小tips:tomcat下JSP页面引用css、js等资源路径404问题
    原生JavaScript实现一个简单的Promise构造函数示例
    canvas图片旋转扩展出原生JS实现移动端横竖屏手写签名示例
  • 原文地址:https://www.cnblogs.com/buexplain/p/4918966.html
Copyright © 2011-2022 走看看