Php开发完全跨站点跨域名单点(SSO)同步登录和注销

时间:2022-04-30 00:47:07

From:http://www.cnblogs.com/JinkoWu/p/5056646.html

先来说说什么是单点登录(SSO)。来自百科的介绍:SSO英文全称Single Sign On,单点登录。SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。它包括可以将这次主要的登录映射到其他应用中用于同一个用户的登录的机制。它是目前比较流行的企业业务整合的解决方案之一。

首先想到的单点登录, 应该就是, 在某个服务器或者站点进行登录, 登录之后携带登录ticket, 跳转到原来登录的站点。原来登录的站点通过远程验证ticket是否合法。这个方法很容易, 只要所有连接都带上ticket参数, 就可以不用登录了。

这样单点登录会有一个局限性, 比如下例场景(如天猫和淘宝):www.a.cn和www.b.net两个站点都在浏览器中打开了, 两个站点都未登录。然后a站点登录, 再切换到b站点的窗口刷新浏览器, 可以发现b站点依然没有登录。因为b站点没有ticket。

如何实现呢? 下面有我自己(Jinko)的个人想法:a站点登录后, 将ticket存到cookie中, 此时a站点是已经登录的。但是b站点无法读取a站点的cookie。因为b站点和a站点是不同根域下的, 这个时候我们应该想到跨域。想到跨域就会想到ajax, canvas多么蛋疼(canvas在将非当前域的img绘制到画布中时进行toDataURL时会有安全限制),他们都会因为跨域安全问题而限制了(当 然还有iframe :))。 解决方案就是jsonp, 每当想到跨域我就想到jsonp。没错, 它确实为跨域而生(要不然也没人用它)。

好, 有了jsonp以上问题就迎刃而解, 思路变成如下:

a站点登录后, b站点通过jsonp获取a站点的ticket, 写到当前站点(b)的cookie里,并执行登录动作,更新页面数据。这时候, 后续的所有页面都可以通过cookie里的ticket进行远程验证。而且从a站点到b站点都无需再url中带上ticket(除了注销登录)。真是方便 多了。a站点注销登录就直接从cookie取ticket并将对于ticket对应的数据删去(一般存于数据库,或者redis、memcache缓存里 面)。在下面的例子里, 为方便我是存于文件 Php开发完全跨站点跨域名单点(SSO)同步登录和注销O(∩_∩)O。

接下来就是代码例子, 我用的是php来实现, 代码结构如下

Php开发完全跨站点跨域名单点(SSO)同步登录和注销

index.php为站点首页, login.php为登录页面, session.lib.php 是自己实现的session存储机制, session-api.php是统一登录接口,.sessioncache目录存的是session缓存文件。看文件目录结构相当简单

要注意的是, 请不要直接用localhost去访问, 要新建两个虚拟主机分别用域名www.a.cn和www.b.net。请修改host文件使它们指向127.0.0.1

以下是代码:

www.a.cn/index.php:

Php开发完全跨站点跨域名单点(SSO)同步登录和注销
 1 <?php
2 /**
3 * Created by PhpStorm.
4 * by Jinko Wu
5 * Date: 2015/12/17
6 */
7 error_reporting(E_ALL ^ E_NOTICE);
8 require "session.lib.php";
9 $session = jsession_start();
10
11 echo '<meta charset="utf-8"/>';
12 if(isset($session)) {
13 echo 'A 您好:' . $session['name'] . '<a href="http://www.a.cn/session-api.php?action=logout&sessid='.jsession_id().'">退出</a>';
14 } else {
15 echo 'A 您还没有登录!'.'<a href="http://www.a.cn/login.php">去登录</a>';
16 }
Php开发完全跨站点跨域名单点(SSO)同步登录和注销

www.a.cn/login.php:

Php开发完全跨站点跨域名单点(SSO)同步登录和注销
 1 <?php
2 /**
3 * Created by PhpStorm.
4 * by Jinko Wu
5 * Date: 2015/12/17
6 */
7 ?>
8 <meta charset="utf-8"/>
9 <form action="session-api.php?action=login" method="post">
10 <input type="text" name="name">
11 <input type="hidden" name="redirect" value="<?php echo $_SERVER['HTTP_REFERER'] ?>">
12 <input type="submit">
13 </form>
Php开发完全跨站点跨域名单点(SSO)同步登录和注销

www.a.cn/session.lib.php:

Php开发完全跨站点跨域名单点(SSO)同步登录和注销
  1 <?php
2 /**
3 * Created by PhpStorm.
4 * by Jinko Wu
5 * Date: 2015/12/17
6 */
7 function jsession_start()
8 {
9 if(!$_COOKIE['__SESSID']) {
10 jsession_regenerate_id();
11 }
12
13 return jsession_update();
14 }
15
16 function jsession_update($session_id=null)
17 {
18 $session_id = $session_id === null ? $_COOKIE['__SESSID'] : $session_id;
19
20 if($session_id == '') {
21 return null;
22 }
23
24 if($session_id && $data = jsession_is_valid($session_id)) {
25 jsession_save($data);
26 setcookie('__SESSID', $session_id, time()+jsession_live_time());
27 return $data;
28 }
29
30 return null;
31 }
32
33 function jsession_regenerate_id()
34 {
35 $sessid = jsession_generate_id();
36
37 if(jsession_id() != '' && file_exists('.sessioncache/' .jsession_id())) {
38 rename('.sessioncache/' .jsession_id(), '.sessioncache/' .$sessid);
39 }
40
41 $_COOKIE['__SESSID'] = $sessid;
42 setcookie('__SESSID', $sessid, time()+jsession_live_time());
43 }
44
45 function jsession_generate_id()
46 {
47 return 's'.base_convert(rand(0, 9999999999).rand(0, 9999999999).rand(0, 9999999999).rand(0, 9999999999), 10, 36);
48 }
49
50 function jsession_id()
51 {
52 return $_COOKIE['__SESSID'];
53 }
54
55 function jsession_live_time()
56 {
57 $gc_maxlifetime = ini_get('session.gc_maxlifetime');
58 $gc_maxlifetime = $gc_maxlifetime == '' ? 1440 : $gc_maxlifetime;
59 return $gc_maxlifetime;
60 }
61
62 function jsession_is_valid($session_id)
63 {
64 $session_id = $session_id === null ? $_COOKIE['__SESSID'] : $session_id;
65
66 if($session_id == '') {
67 return false;
68 }
69
70 if(file_exists('.sessioncache/' .$session_id)) {
71 $data = unserialize(@file_get_contents('.sessioncache/' . $session_id));
72 return time() <= $data['time'] ? $data['data'] : false;
73 } else {
74 return false;
75 }
76 }
77
78 function jsession_data($session_id=null)
79 {
80 $session_id = $session_id === null ? $_COOKIE['__SESSID'] : $session_id;
81
82 if($session_id == '') {
83 return null;
84 }
85
86 if($data = jsession_is_valid($session_id)) {
87 return $data;
88 }
89
90 return null;
91 }
92
93 function jsession_save($data)
94 {
95
96 if(!is_dir('.sessioncache')) {
97 mkdir('.sessioncache', 0777);
98 }
99
100 if($_COOKIE['__SESSID'] == '') {
101 return null;
102 }
103
104 $file = '.sessioncache/'.$_COOKIE['__SESSID'];
105 $fp = fopen($file , 'w');
106
107 if(flock($fp , LOCK_EX)) {
108 fwrite($fp, serialize(array('time' => time() + jsession_live_time(), 'data' => $data)));
109 flock($fp, LOCK_UN);
110 }
111
112 fclose($fp);
113 return $data;
114 }
115
116 function jsession_destory($session_id)
117 {
118 if($session_id == '') {
119 return ;
120 }
121
122 if($session_id == $_COOKIE['__SESSID']) {
123 setcookie('__SESSID', '');
124 $_COOKIE['__SESSID'] = null;
125 }
126
127 if(file_exists('.sessioncache/' .$session_id)) {
128 @unlink('.sessioncache/' .$session_id);
129 }
130 }
Php开发完全跨站点跨域名单点(SSO)同步登录和注销

www.a.cn/session-api.php:

Php开发完全跨站点跨域名单点(SSO)同步登录和注销
 1 <?php
2 /**
3 * Created by PhpStorm.
4 * by Jinko Wu
5 * Date: 2015/12/17
6 */
7 error_reporting(E_ALL ^ E_NOTICE);
8 require 'session.lib.php';
9
10 if($_REQUEST['action'] == 'check') {
11 $session = jsession_is_valid($_REQUEST['id']);
12 echo json_encode(array('session' => $session));
13
14 } else if($_REQUEST['action'] == 'logout') {
15 if($_REQUEST['sessid'] !== null) {
16 jsession_destory($_REQUEST['sessid']);
17 }
18
19 echo '<meta charset="utf-8"/>';
20 echo '退出登录成功, 正在跳转...';
21 $_SERVER['HTTP_REFERER'] = $_SERVER['HTTP_REFERER'] == '' ? '/' : $_SERVER['HTTP_REFERER'];
22 echo '<script type="text/javascript">window.location.href = "' . $_SERVER['HTTP_REFERER'] . '";</script>';
23
24 } else if($_REQUEST['action'] == 'login') {
25 jsession_start();
26 $data = jsession_save(array('name' => trim($_REQUEST['name'])));
27 $redirect = $_REQUEST['redirect'] ? $_REQUEST['redirect'] : 'http://www.a.cn';
28 echo '<meta charset="UTF-8"><script type="text/javascript">window.location.href = "'.$redirect.'";</script>';
29
30 } else {
31 $session = jsession_start();
32
33 if($session && trim($_REQUEST['call']) != '' && jsession_id() != '') {
34 echo $_REQUEST['call'] . '('.json_encode(array('sessid' => jsession_id(), 'session' => $session)).')';
35 }
36 }
Php开发完全跨站点跨域名单点(SSO)同步登录和注销

www.b.net/index.php:

Php开发完全跨站点跨域名单点(SSO)同步登录和注销
 1 <?php
2 /**
3 * Created by PhpStorm.
4 * by Jinko Wu
5 * Date: 2015/12/17
6 */
7 ?>
8 <meta charset="utf-8"/>
9 <script type="text/javascript">
10 function setCookie(name,value)
11 {
12 var Days = 30;
13 var exp = new Date();
14 exp.setTime(exp.getTime() + Days*24*60*60*1000);
15 document.cookie = name + "="+ escape (value) + ";expires=" + exp.toGMTString();
16 }
17
18 //jsonp 登录函数
19 function jsonp_do_login(data)
20 {
21 document.getElementById('name').innerHTML = 'B 您好:' + data.session.name + '<a href="http://www.a.cn/session-api.php?action=logout&sessid='+data.sessid+'">退出</a>';
22 console.log(data);
23 setCookie('__SESSID', data.sessid);
24 }
25 </script>
26 <?php
27 error_reporting(E_ALL ^ E_NOTICE);
28 session_start();
29 $session = check_session();
30 $sessid = $_COOKIE['__SESSID'];
31
32 if($session) {
33 echo 'B 您好:' . $session['name'] . '<a href="http://www.a.cn/session-api.php?action=logout&sessid='.$sessid.'">退出</a>';
34 } else {
35 echo '<span id="name">B 您还没有登录!<a href="http://www.a.cn/login.php">去登录</a></span>';
36 }
37
38 function check_session()
39 {
40 $sessid = $_COOKIE['__SESSID'];
41 $json = file_get_contents("http://www.a.cn/session-api.php?id=$sessid&action=check");
42 $json_data = json_decode($json, true);
43
44 if($json_data == null || empty($json_data['session'])) {
45 return false;
46 } else {
47 return $json_data['session'];
48 }
49 }
50
51 ?>
52
53 <?php if(!$session): ?>
54 <script type="text/javascript" src="http://www.a.cn/session-api.php?call=jsonp_do_login&<?php echo rand()?>"></script>
55 <?php endif; ?>
Php开发完全跨站点跨域名单点(SSO)同步登录和注销

点击这里下载打包好的代码: http://files.cnblogs.com/files/JinkoWu/MultiSiteSingleLogin.zip

最后附上一张示例图片:

Php开发完全跨站点跨域名单点(SSO)同步登录和注销

Php开发完全跨站点跨域名单点(SSO)同步登录和注销的更多相关文章

  1. 完全跨站点跨域名单点&lpar;SSO&rpar;同步登录和注销

    先来说说什么是单点登录(SSO).来自百科的介绍:SSO英文全称Single Sign On,单点登录.SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统.它包括可以将这次主 ...

  2. 基于Swift语言开发微信、QQ和微博的SSO授权登录代码分析

    前言 Swift 语言,怎么说呢,有一种先接受后排斥.又欢迎的感觉,纵观国外大牛开源框架或项目演示,Swift差点儿占领了多半,而国内尽管出现非常多相关技术介绍和教程,可是在真正项目开发中使用的占领非 ...

  3. 网站跨站点单点登录实现--cookie

    至于什么是单点登录,举个例子,如果你登录了msn messenger,访问hotmail邮件就不用在此登录.一般单点登录都需要有一个独立的登录站点,一般具有独立的域名,专门的进行注册,登录,注销等操作 ...

  4. IIS下设置跨域访问问题--Access-Control-Allow-Origin 站点跨域请求的问题

    背景: 最近 开发中遇到新需求,把公司的OA系统迁移一套到小程序上面去 有些功能的信息是在小程序 查看 但是文件是在pc端上传的 例如:领导在外出办公 使用小程序查看xxxx.pdf文件  这个时候就 ...

  5. 跨站点端口攻击 – XSPA(SSPA)

    许多Web应用程序提供的功能将数据从其他Web服务器,由于种种原因.下载XML提要,从远程服务器,Web应用程序可以使用用户指定的URL,获取图像,此功能可能会被滥用,使制作的查询使用易受攻击的Web ...

  6. asp&period;net关于Cookie跨域(域名)的问题

    Cookie是一个伟大的发明,它允许Web开发者保留他们的用户的登录状态.但是当你的站点有一个以上的域名时就会出现问题了.在Cookie规范上 说,一个cookie只能用于一个域名,不能够发给其它的域 ...

  7. ASP&period;NET Core中的OWASP Top 10 十大风险-跨站点脚本攻击 &lpar;XSS&rpar;

    不定时更新翻译系列,此系列更新毫无时间规律,文笔菜翻译菜求各位看官老爷们轻喷,如觉得我翻译有问题请挪步原博客地址 本博文翻译自: https://dotnetcoretutorials.com/201 ...

  8. IBM Rational AppScan:跨站点脚本攻击深入解析

    IBM Rational AppScan:跨站点脚本攻击深入解析    了解黑客如何启动跨站点脚本攻击(cross-site scripting,XSS),该攻击危害(及不危害)什么,如何检测它们,以 ...

  9. vue 开发和生产的跨域问题

    开发阶段 在开发环境与后端调试的时候难免会遇到跨域问题,在 vue 项目中常用的是 proxyTable,这个用起来很方便. 打开 config 文件夹下面的 index.js,找到 dev 开发模式 ...

随机推荐

  1. php--opp--2&period;什么是类,什么是对象,类和对象这间的关系

    类的概念:类是具有相同属性和服务的一组对象的集合.它为属于该类的所有对象提供了统一的抽象描述,其内部包括属性和服务两个主要部分.在面向对象的编程语言中,类是一个独立的程序单位,它应该有一个类名并包括属 ...

  2. python小练习之二

    title: python小练习之二 tags: 新建,模板,小书匠 grammar_cjkRuby: true --- python小练习之二 需求:实现用户登录,用户名和密码保存到文件里,连续输入 ...

  3. 【转】百度站长平台MIP引入工具使用心得

    MIP引入主动推送流程 对于 MIP 站点改造好了,我们如何提交数据,并且 MIP 提交后,我们能得到哪些数据的反馈,在这里简单的写一篇文章,说一下. 改造 MIP,我们一般是添加了一个二级域名站点进 ...

  4. 常用类-API文档-Integer

    package IntegerTest;import java.util.Base64.Decoder; public class test01 { /** * 包装类的基本数据类型 * int =& ...

  5. Leha and another game about graph CodeForces - 840B &lpar;dfs&rpar;

    链接 大意: 给定无向连通图, 每个点有权值$d_i$($-1\leq d_i \leq 1$), 求选择一个边的集合, 使得删除边集外的所有边后, $d_i$不为-1的点的度数模2等于权值 首先要注 ...

  6. Mybatis连接Oracle实现增删改查实践

    1. 首先要在项目中增加Mybatis和Oracle的Jar文件 这里我使用的版本为ojdbc7 Mybatis版本为:3.2.4 2. 在Oracle中创建User表 create table T_ ...

  7. java 在Excel中插入图片 POI实现

    一.POI简介 Jakarta POI 是apache的子项目,目标是处理ole2对象.它提供了一组操纵Windows文档的Java API 目前比较成熟的是HSSF接口,处理MS Excel(97- ...

  8. 01、dos命令行的常用命令

    cd 进入指定目录cd..  返回上一级目录cd\   退回盘符根目录dir        列出当前目录下的文件以及文件夹md       创建目录rd 删除目录del   删除文件cls       ...

  9. centos 7&period;3 安装vmtools,解决无法编译共享文件夹模块

    环境说明: vmware 12.5.0 build-4352439 centos 7.3.1611   64位,内核版本:Linux version 3.10.0-514.16.1.el7.x86_6 ...

  10. kafka监控工具kafka-manager

    1.几个kafka监控工具 Kafka Web Console:监控功能较为全面,可以预览消息,监控Offset.Lag等信息,但存在bug,不建议在生产环境中使用. Kafka Manager:偏向 ...