1 概述
      对于单点登录的机制和原理就不在这里赘述了。本文仅是对于单点登录问题研究所得的心得进行一下总结。
想要实现单点登录可以采用的方式有很多种:
1 利用成熟的软件框架(CAS,OPENSSO等)
2自己建设单点登录框架(像sohu的单点登录)
3 还有就是最简单的使用URL模拟登录。

但是各种方式都各有利弊。最主要的问题是大部分实现方式都需要对单点登录目标系统进行修改,或者在目标系统中放入单点登录代码。如果我们自己对目标系统没有控制能力,那么与目标系统的沟通就成为最大的阻碍。
      如果可以不修改目标系统,或者可以不在目标系统放入代码就可以登录就是最理想的单点登录。基于这一问题,那么建立模仿登录请求的URL进行登录就成为相对 较佳的方案。为什么说是“相对较佳”,因为利用URL进行登录,基本上都有页面的刷新或者是跳转。那么单点登录的设计将成为瓶颈,尤其是在想要设计成无刷 新登录或者可以Session保持随时进入目标系统,将给系统带来更多的限制。

实际上,近期主要是针对这一问题进行了大量的研究,采用了各种方法进行尝试。但是并没有得到实质性的成果,主要存在的问题是:浏览器基于安全考虑所采用的“同源策略”(Same Origin Policy)。

下面我分别根据所采用的方法进行阐述

2 跨域解决对策
2.1 Ajax
      Ajax异步发送请求是最先采用的方法。原有的单点登录方式,是在目标系统放置代码。通过URL访问该代码,在由该代码发送Ajax请求进行登录。
      因为该种方式,需要在目标系统放置代码,这样不能满足我们的要求,所以尝试将Ajax发送请求登录代码移到“源系统”(即具备单点登录功能的系统,就是我 们的门户系统)。但是请求根本无法发出,浏览器直接就弹出提示框:“该页正在访问其控制范围之外的数据,这有些危险,是否继续"。Ajax本身实际上是通 过XMLHttpRequest对象来进行数据的交互,而浏览器出于安全考虑,不允许js代码进行跨域操作,所以会警告。

有一种方法,用服务器端的XmlHttpRequest代理实现跨域访问。
      我们不能在浏览器端直接使用AJAX来跨域访问资源,但是在服务器端是没有这种跨域安全限制的。所以,只需要让服务器端帮我们完成“跨域访问”的工作,然 后在浏览器端用AJAX获取服务器端“跨域访问”的结果就可以了。这就是所谓的在服务器端创建一个XmlHttpRequest代理,通过这个代理来访问 其他域名下的资源。这里引用Yahoo! JavaScript Developer Center上的几张图来进一步说明这个方案:

使用XmlHttpRequest访问同一域名下的资源: 
 

使用XmlHttpRequest跨域访问资源: 
 

用服务器端的XmlHttpRequest代理来跨域访问资源:


 
      编写服务器端XmlHttpRequest代理的具体过程就不赘述了,无非是创建一个自定义的HTTP请求。
      实际上,该方法并没有从本质上解决Ajax的跨域问题。

2.2 JavaScript
      比较常用的一种解决跨域的方法是用动态script标签实现客户端的跨域访问 。
      很明显,上一个方案必须要在服务器端做相应的改动才能实现跨域访问。但是很多时候是不能改动服务器端的源代码,那么上一个方案就不能满足需求了。

我们应该能注意到,虽然浏览器有跨域访问的限制,但是我们是可以通过script标签远程引用其他域名下的脚本文件的。而且,script标签的src属 性不一定必须是一个存在的js文件,也可以是一个http handler的url,只要这个http handler返回的是一个text/javascript类型的响应就可以了。

这样,我们的第二个方案就浮出水面了。这个和上个的区别就是请求是使用<script>标签来请求的,这个要求也是两个域都是由你来开发才 行。原理就是JS文件注入,在本域内的a内生成一个JS标签,它的SRC指向请求的另外一个域的某个页面b,b返回数据即可,可以直接返回JS的代码。因 为script的src属性是可以跨域的。具体看代码,这个也比较简单。

2.3 Iframe
Iframe具体使用情况有:
一、本域和子域的相互访问: www.aa.com和book.aa.com
二、本域和其他域的相互访问: www.aa.com和www.bb.com 用 iframe

第一种情况如果想做到数据的交互,那么www.aa.com和book.aa.com必须由你来开发才可以。可以将book.aa.com用iframe添加到www.aa.com的某个页面下,在www.aa.com和 iframe里面都加上document.domain = "aa.com",这样就可以统一域了,可以实现跨域访问。就和平时同一个域中镶嵌iframe一样,直接调用里面的JS就可以了。(这个办法我没有尝 试,不过理论可行,而且下面的跨子域Cookie方法似乎更好)

第二种情况当两个域不同时,如果想相互调用,那么同样需要两个域都是由你来开发才可以。用iframe可以实现数据的互相调用。解决方案就是用window.location对象的hash属性。hash属性就是http://domian/web/a.htm#dshakjdhsjka里 面的#dshakjdhsjka。利用JS改变hash值网页不会刷新,可以这样实现通过JS访问hash值来做到通信。不过除了IE之外其他大部分浏览 器只要改变hash就会记录历史,你在前进和后退时就需要处理,非常麻烦。不过再做简单的处理时还是可以用的,具体的代码我再下面有下载。大体的过程是页 面a和页面b在不同域下,b通过iframe添加到a里,a通过JS修改iframe的hash值,b里面做一个监听(因为JS只能修改hash,数据是 否改变只能由b自己来判断),检测到b的hash值被修改了,得到修改的值,经过处理返回a需要的值,再来修改a的hash值(这个地方要注意,如果a本 身是那种查询页面的话比如http://domian/web/a.aspx?id=3,在b中直接parent.window.location是无法取得数据的,同样报没有权限的错误,需要a把这个传过来,所以也比较麻烦),同样a里面也要做监听,如果hash变化的话就取得返回的数据,再做相应的处理。

2.4 HttpClient
      下面所采用的办法是利用Apache的HttpClient进行登录。
      通常,我们使用A系统中的URL进行单点登录的流程是这样的。首先创建模拟A系统中登录表单提交的URL进行登录(我们把这个URL叫做URL1)。如果 登录成功的话,用A系统的正常访问URL访问该网站就可以看到已经是登录状态(我们把这个URL叫做URL2)。
      其原理就是HTTP协议的原理,在我们利用URL1进行访问以后,服务器就会为该用户创建一个Session,并在响应中设置“Set-Cookie”头 信息,信息中包含对应的SessionID。浏览器就会根据该信息在客户端生成Cookie。当我们再访问URL2时,浏览器就会判断该会话中是否已创建 Cookie,如果已经创建就会在请求中添加Cookie头信息,信息中包含对应的SessionID。服务器在处理消息时判断SessionID是否相 同,相同就认为是同一会话,同一个人。
这就是现在解决HTTP协议无状态的办法。但是这个前提是在使用同一个浏览器。就像现在的IE7,虽然可能会打开多个Tab页,但是还是同一个浏览器。

利用HttpClient确实可以模拟发送请求,登录进入目标系统。但是HttpClient的原理是每建立一个链接,相当于新打开一个浏览器。那么按照 上面所说流程分别访问URL1和URL2将会被模拟成打开两个浏览器,换句话说在访问URL2时,就不会带上Cookie的消息头,服务器就会认为不是同 一个会话,也就不会模拟出成功的登录状态。

根据上面的描述,解决问题的症结就在于:在发送访问URL2的请求时可以带上URL1返回的Cookie信息即可。

想要在访问URL2的时候带上Cookie头信息,有以下几个办法
1、 在访问URL1之后,在客户端创建Cookie
2、 在访问URL2时,在消息头中加入Cookie头信息。
3、 在访问URL2时,进行URL重写,在其后加入Cookie头中的信息。

通常情况下,以上三种操作都不需要我们自己做,完全可以由服务器和系统自动完成。但是我们所要处理的情况是在B系统中,通过访问A系统的URL1和URL2登录到A系统中,这样就会产生问题。

2.5 跨域Cookie
1、从B系统中访问A系统的URL1,出于同源策略的安全考虑,浏览器会禁止A系统生成Cookie。
2、很不幸的是J2EE并没有提供在请求头中加入Cookie头的方法。
3、该方法是唯一可行的,但是如果B系统引用A系统的类似于URL2的URL过多,URL重写是一块加到的工作了。
      总结的来说,就是因为同源策略导致不能共享Cookie,也因此不能维持Session的联通。但是同源策略是支持跨子域Cookie的。

2.6 跨子域Cookie
      所谓跨子域登录,A,B站点和P站点位于同一个域下面,比如A站点为http://blog.yizhu2000.com,B站点为 http://forum.yizhu2000.com, 他们和登录站点P的关系可以看到,都是属于同一个父域,yizhu2000.com,不同的是子域不同,一个为blog,一个为forum,一个是 passport我们先看看最常用的非跨站点普通登录的情况,一般登录验证通过后,一般会将你的用户名和一些用户信息,通过某一密钥进行加密,写在本地, 也就是一个加密的cookie,我们把这个cookie叫做--票(ticket)。

需要判断用户是否登录的页面,需要读取这个ticket,并从其中解密出用户信息,如果ticket不存在,或者无法解密,意味着用户 没有登录,或者登录信息不正确,这时就要跳转到登录页面进行登录,在这里加密的作用有两个,一是防止用户信息被不怀好意者看到,二是保证ticket不会 被伪造,后者其实更为重要,加密后,各个应用需要采用与加密同样的密钥进行解密,如果不知道密钥,就不能伪造出ticket,(注:加密和解密的密钥有可 能不同,取决于采用什么加密算法,如果是对称加密,则为同一密钥,如果是非对称,就不同了,一般用私钥加密,公钥解密,但是无论怎样,密钥都只有内部知 道,这样伪造者既无法伪造也无法解密ticket)

跨子域的单点登录,和上述普通登录的过程没有什么不同,唯一不同的是写cookie时,由于登录站点P和应用A处于不同的子域,P站写入的cookie的 域为passport.yizhu2000.net,而A站点为forum.yizhu2000.net,A在判断用户登录时无法读到P站点的 ticket

解决方法非常简单,当Login完成后P站点写ticket的时候,只需把cookie的域设为他们共同的父域,yizhu2000.net就可以了:cookie.domain="yizhu2000.net",A站点自然就可以读到这个ticket了

2.7 P3P
      在网上查过资料,有一种方法是可以做到不同域的Cookie设置,其方法就是在响应头中加入P3P头信息。设置方法举例如下:

Step1:
      首先在hosts文件中设置(其中的192.168.73.1为您本机的ip,写成127.0.0.1不行。) 只是举例在真正服务器上不需要这样。
192.168.73.1 www.a.com
192.168.73.1 www.b.com

Step2:编写文件 b_setcookie.jsp

[java] view plaincopy
  1. <%@ page contentType="text/html; charset=utf-8" %>
  2. <%
  3. response.addHeader("Cache-Control", "no-cache");
  4. response.addHeader("Expires", "Thu, 01 Jan 1970 00:00:01 GMT");
  5. String ssocookie="www.sso12345678910.com";
  6. %>
  7. <mce:script src="http://www.a.com/mp/test/a_setcookie.jsp?id=<%=ssocookie%><!--
  8. ">
  9. // --></mce:script>

Step3:编写文件 a_setcookie.jsp

[java] view plaincopy
  1. <%
  2. response.setHeader("P3P","CP=/"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR/"");
  3. String domainId=request.getParameter("id");
  4. Cookie _cookie=new Cookie("test",domainId);
  5. _cookie.setMaxAge(30*60*100);
  6. _cookie.setPath("/");
  7. response.addCookie(_cookie);
  8. %>

Step4:编写文件 a_getcookie.jsp

[java] view plaincopy
  1. <%@ page contentType="text/html; charset=utf-8" %>
  2. <%
  3. Cookie cookies[]=request.getCookies();Cookie sCookie=null;
  4. String sname=null;
  5. String name=null;
  6. if(cookies==null) // 如果没有任何cookie
  7. out.print("none any cookie");
  8. else {
  9. out.print(cookies.length + "<br>");
  10. for(int i=0;i<cookies.length; i++) {
  11. sCookie=cookies[i];
  12. sname=sCookie.getName();
  13. name = sCookie.getValue();
  14. out.println("comment==>>>"+sCookie.getComment()+"/n");
  15. out.println("getDomain==>>>"+sCookie.getDomain()+"/n");
  16. out.println("getSecure==>>"+sCookie.getSecure()+"/n");
  17. out.println("getVersion==>>"+sCookie.getVersion()+"/n");
  18. out.println("cookiename==>>"+sname + "->" + "cookievalue==>>>"+name + "<br>");
  19. }
  20. }
  21. %>

Step5:测试
依次请求
http://www.b.com/mp/test/b_setcookie.jsp
http://www.a.com/mp/test/a_getcookie.jsp
便可看到通过跨域设置的cookie的值!
      这种方法虽然可以实现跨域设置Cookie,但还是需要在目标系统进行代码的注入。

3 题外话
       实际上水晶易表Flash不能跨域访问WebService获取数角也是因为类似于同源策略的安全沙盒问题引起。
 对于安全沙盒问题,倒是也有相应的解决办法。
       如果想要在Flash里面跨域获取数据,就必须在对方server上配置crossdomain.xml。具体来说,比如你的Flash在domain A下面,而你想要访问domain B暴露的web service,那么domain B的server根目录下必须要有一个crossdomain.xml文件来配置说你有这个权限。这个是Flash Player的安全限制。
       对于Flash Player 9之前的版本,这个crossdomain.xml文件大概如下:

[xhtml] view plaincopy
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd" >
  3. <cross-domain-policy>
  4. <allow-access-from domain="*" secure="true" />
  5. </cross-domain-policy>

以上配置允许所有domain访问当前server所暴露的数据(比如web service)。你可以在domain属性里面指定特殊的规则。secure属性用来设置你所暴露的数据是否走https协议。
      但是对于Flash Player 9而言,crossdomain.xml文件内容出现了较大的变化,原因是Flash Player 9的security机制有所改变。所以当我用Flex 3调用cross domain的web service时,还使用上面的crossdomain.xml文件,结果就报错说security error。于是稍微研究了一下,得到如下解决方案,其实就是要改变crossdomain.xml的内容:

[xhtml] view plaincopy
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd" >
  3. <cross-domain-policy>
  4. <site-control permitted-cross-domain-policies="all" />
  5. <allow-access-from domain="*" />
  6. <allow-http-request-headers-from domain="*" headers="*"/>
  7. </cross-domain-policy>

以上是Flash Player 9所要求的crossdomain.xml的内容。可以看到多了两个tag。其中site-control是可选的,但是allow-http- request-headers-from对于cross domain的web service确实必须的。如果没有允许header,就会像我之前一样报错。这些配置项的具体含义以及其他可选配置项,可以参考http://www.adobe.com/devnet/flashplayer/articles/flash_player_9_security.pdf。
      当然在生成的Flash当中,需要有代码来调用相应的crossdomain.xml。但是水晶易表所导出的Flash当中,并不包含该代码。

转载于:https://www.cnblogs.com/duanxz/p/4029488.html

单点登录相关问题总结相关推荐

  1. oauth2 单点登录_Spring Security Oauth2和Spring Boot实现单点登录

    最近在学习单点登录相关,调查了一下目前流行的单点登录解决方案:cas 和 oauth2,文章主要介绍oauth2 单点登录.希望这篇文章能帮助大家学习相关内容. 我们将使用两个单独的应用程序: 授权服 ...

  2. 共同父域下的单点登录

    共同父域下的单点登录 标签: SSO 2014-03-04 22:38 12686人阅读 评论(17) 收藏 举报 分类: Java Web(12) 作者同类文章X 版权声明:本博客所有的原创文章,作 ...

  3. 如何设计一个单点登录系统

    本文来说下如何设计一个单点登录系统 文章目录 概述 JWT的组成 头部(Header) 载荷(Payload) 签名(签名) 签名的目的 信息会暴露 JWT的适用场景 用户认证八步走 和Session ...

  4. 【运维小知识】单点登录是什么意思?有什么作用?

    很多刚入行的运维小伙伴,对于单点登录相关知识不是很了解,例如单点登录是什么意思?有什么作用?单点登录与多点登录有什么区别?这里我们小编就给大家简单回答,希望可以加深大家的了解. 单点登录是什么意思? ...

  5. python 单点登录

    前言   最近项目中小组负责开发的知识图谱子系统需要增加单点登录这个功能,由于我也是头一次开发这个,也请教了java后端大佬,再根据自己具体业务和使用的框架(fastapi)完成了任务,现在回过头来整 ...

  6. SAML单点登录-spring-security-saml客户端SP

    SAML单点登录-spring-security-saml客户端SP 使用spring-security-saml搭建SAML协议的客户端,该依赖是spring框架的官方库,配置方便.文档详细.提供了 ...

  7. Java开发 - 单点登录初体验(Spring Security + JWT)

    目录​​​​​​​ 前言 为什么要登录 登录的种类 Cookie-Session Cookie-Session-local storage JWT令牌 几种登陆总结 用户身份认证与授权 创建工程 添加 ...

  8. CAS单点登录原理解析及相关配置

    1.基于Cookie的单点登录的回顾 基于Cookie的单点登录核心原理: 将用户名密码加密之后存于Cookie中,之后访问网站时在过滤器(filter)中校验用户权限,如果没有权限则从Cookie中 ...

  9. [转]单点登录原理与简单实现

    一.单系统登录机制 1.http无状态协议 web应用采用browser/server架构,http作为通信协议.http是无状态协议,浏览器的每一次请求,服务器会独立处理,不与之前或之后的请求产生关 ...

  10. 单点登录与权限管理本质:session和cookie介绍

    本篇开始写「单点登录与权限管理」系列的第一部分:单点登录与权限管理本质,这部分主要介绍相关的知识概念.抽象的处理过程.常见的实现框架.通过这部分的介绍,能够对单点登录与权限管理有整体上的了解,对其相关 ...

最新文章

  1. 掌握图神经网络GNN基本,看这篇文章就够了
  2. .NET跨平台之旅:将示例站点从ASP.NET 5 Beta7升级至RC1
  3. 让开发自动化持续重构 --使用静态分析工具识别代码味道
  4. dfs题目这样去解题,秒杀leetcode题目
  5. java课程设计进程管理_Java课设总结(个人版)
  6. 顺序容器STL::list用法
  7. linux openssl离线安装路径,离线安装openssl-devel顺序
  8. postman参数化--上一个接口返回的数据作为下一个接口的参数
  9. gif透明背景动画_图片的不同格式:JPG、PNG、GIF都有什么区别?
  10. 浅析基本事实表的ETL处理
  11. 前阿里财务人告诉你:抛弃Excel,原来报表竟然还能这么快
  12. 初级篇第三期:初识UI
  13. 远场(far-field)语音识别的主流技术有哪些?
  14. 一个自动动态播放图片的类(downmoon)新增图片效果
  15. Excel批量生成minitab图表(自动化)
  16. BUUCTF------相册
  17. android netd firewall 分析,第2章 深入理解Netd
  18. 一个简单的时间片轮转多道程序内核代码
  19. STM32L476低功耗—进入STOP2模式4s后LPTIM中断唤醒+功率实测
  20. 1080i、720p、1080p、N制、P制、帧率、高清电视、全高清

热门文章

  1. prometheus 筛选不同的cpu核心
  2. JDBC05 ResultSet结果集
  3. 模板引擎thymeleaf和freemarker
  4. SpringSecurity安全框架的笔记
  5. 九、Oracle学习笔记:聚合函数
  6. 我去,这么简单的条件表达式竟然也有这么多坑
  7. jenkins 部署 并执行npm run dev 项目时,execute shell自动结束进程问题
  8. 适配器模式之状态模式
  9. JavaScript三目运算符的使用
  10. Android 动态显示和隐藏软键盘