热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【No.1】基于Cookie的单点登录(SSO)

2019独角兽企业重金招聘Python工程师标准这篇主要说明基于Cookie的单点登录实现,以及Cookie的一些特性以及使用说明。1、Cookie是什么&#x

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

这篇主要说明基于COOKIE的单点登录实现,以及COOKIE的一些特性以及使用说明。

1、COOKIE是什么,如何工作的

      在程序中,会话跟踪是很重要的事情。理论上,一个用户的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能混淆。例如,用户A在超市购买的任何商品都应该放在A的购物车内,不论是用户A什么时间购买的,这都是属于同一个会话的,不能放入用户B或用户C的购物车内,这不属于同一个会话。而Web应用程序是使用HTTP协议传输数据的。HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。即用户A购买了一件商品放入购物车内,当再次购买商品时服务器已经无法判断该购买行为是属于用户A的会话还是用户B的会话了。要跟踪该会话,必须引入一种机制。
      COOKIE就是这样的一种机制。它可以弥补HTTP协议无状态的不足。在Session出现之前,基本上所有的网站都采用COOKIE来跟踪会话。

      COOKIE意为“甜饼”,是由W3C组织提出,最早由Netscape社区发展的一种机制。目前COOKIE已经成为标准,所有的主流浏览器如IE、Netscape、Firefox、Opera等都支持COOKIE。

 

2、现实生活中类似于COOKIE的举例

      例如你所在的城市可能有很多便利店(web服务器),便利店一般都会举行一些活动,例如积满15次消费金额在20元以上,送毛绒公仔一只。但是客户(浏览器)特别多,便利店不可能每个都记住,于是便利店就制作一个卡片(COOKIE)交给客户。之后每次客户来买东西的人时候就把卡片提交给便利店(web服务器),于是便利店就知道你目前的状态信息,这样就做到了跟踪会话。

      从上面可以看出,COOKIE是由浏览器管理的,web服务器将数据交给浏览器,浏览器可以把数据保存起来,等到下次访问的时候自动提交。

      

如上图中,在整个交互中的流程如下:

      第一步:浏览器发送信息(例如:用户名密码)提交给服务器。

      第二步:服务器接收到之后,发送一个命令给浏览器,告诉他你要把相关的信息存到COOKIE里面。

      第三步:如果是零时性的就存于浏览器内存中,重启浏览器信息就消失了。

      第四步:如果是需要存很久,例如两周之内自动登陆这种需求,则将信息存于硬盘上。

      第五步:当在此访问浏览器时,则自动将COOKIE发送给服务器。

 

3、各浏览器都把COOKIE放到了哪里

以Windows7为例:

      IE浏览器:%APPDATA%\Microsoft\Windows\COOKIEs\ 目录中的xxx.txt文件 (IE浏览器分开存放的)。

      火狐浏览器:%APPDATA%\Mozilla\Firefox\Profiles\ 目录中的xxx.default目录,名为COOKIEs.sqlite的文件。

      谷歌浏览器:%LOCALAPPDATA%\Google\Chrome\User Data\Default\ 目录中,名为COOKIEs的文件。

在IE浏览器中,IE将各个站点的COOKIE分别保存为一个XXX.txt这样的纯文本文件(文件个数可能很多,但文件大小都较小);而Firefox和Chrome是将所有的COOKIE都保存在一个文件中(文件大小较大),该文件的格式为SQLite3数据库格式的文件。

 

4、实际开发项目中如何使用代码操作COOKIE

在Java中,Web项目提供了一个类:javax.servlet.http.COOKIE 该类就与COOKIE对应。下面给出Servlet中操作COOKIE示例代码:

package com.csdn.cas;import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.COOKIE;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class LoginServlet extends HttpServlet {private static final long serialVersionUID = 1L;@Overridepublic void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 获取请求参数String userName = req.getParameter("userName");String passwd = req.getParameter("passwd");// 创建COOKIE对象COOKIE userInfoCOOKIE = new COOKIE("userInfo", userName + ":" + passwd);// 返回给浏览器的数据中添加COOKIE信息resp.addCOOKIE(userInfoCOOKIE);}
}

上面就是简单的操作COOKIE的代码,我们将这个servlet部署到tomcat中,使用谷歌,并观察相关的COOKIE信息(使用F12,有调试工具)。

      

观察第一次的访问情况,在响应头里面多出来一个Set-COOKIE:的东东,浏览器就根据这个这个COOKIE信息保留了下来。

      

当再一次访问这个网站时,则请求头中多了第一次返回的COOKIE信息,响应中之所以还有Set-COOKIE,是因为我们访问的是同一个代码。

如果你把浏览器关了,在访问这个地址,那么请求中是不会带有COOKIE信息的,因为浏览器只是零时性的将数据保存在内存中。如果需要保存在硬盘上则需要特殊处理。

 

5、COOKIE的特性

5.1、COOKIE不能跨域

      例如:你访问www.baidu.com,百度给你发了一个COOKIE,你在访问www.google.com你是不能把百度发给你的COOKIE带到谷歌的服务器上的。

      需要特别注意的是:images.google.com与www.google.com同属于google,但是他们的域名不一样,二者同样也不能操作彼此的COOKIE,浏览器在访问的时候,会根据访问地址自动携带相关域名的COOKIE过去。

      注意:有时候你会发现有些特殊的网站,类似你登录了www.google.com但是你当问images.google.com时,www.google.com的COOKIE被带到了images.google.com,这是因为做了特殊的处理,下面会详细说。

5.2、其他相关特性请参照博客

      传送门:http://blog.csdn.net/fangaoxin/article/details/6952954/

      

6、利用COOKIE的特性实现单点登录的原理

上图就是一个利用COOKIE做单点登录的原理图,案例为用户dgh(密码123)登录www.qiandu.com,之后又登录mail.qiandu.com。流程如下:

      第一步:用户输入用户名/密码(dgh/123)登录到www.qiandu.com。

      第二步:www.qiandu.com处理登录逻辑,并且将用户信息通过COOKIE的方式返回到客户端(最好加密用户信息)。

      第三步:用户访问mail.qiandu.com,浏览器自动将用户信息携带到mail.qiandu.com,通过过滤器(filter)处理用户的登录请求。

      第四步:过滤器从COOKIE中获取用户信息,登录,返回用户访问界面。这样用户就只登录一次,就访问了两个网站了。

 

7、COOKIE实现单点登录的代码实现

1、首先是一个登录的Servlet,简单实现,只要用户名密码相同则登录成功,并将信息写到COOKIE中。

package com.csdn.cas;import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.COOKIE;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;public class LoginServlet extends HttpServlet {private static final long serialVersionUID = 1L;@Overridepublic void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 获取请求参数String userName = req.getParameter("userName");String passwd = req.getParameter("passwd");resp.setCharacterEncoding("UTF-8");resp.setContentType("text/html;charset=UTF-8");HttpSession session = req.getSession();// 只有用户名与密码相同,则登录成功if(userName.equals(passwd)){// 创建COOKIE对象COOKIE userInfoCOOKIE = new COOKIE("userInfo", userName + ":" + passwd);// 这里很重要,不设置无法夸子域 这里最好以 .开头,例如.qiandu.com// 谷歌浏览器自动给他添加了.userInfoCOOKIE.setDomain("qiandu.com");// 返回给浏览器的数据中添加COOKIE信息resp.addCOOKIE(userInfoCOOKIE);session.setAttribute("userName", userName + ",登录成功");}else {session.setAttribute("userName", userName + ",登录失败");}req.getRequestDispatcher("/index.jsp").forward(req, resp);}
}

 

2、写一个Filter,过滤处理所有的请求,如果是登录请求则到登录页,否则尝试登陆。

package com.csdn.cas;import java.io.IOException;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.COOKIE;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;public class LoginFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException { }@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {HttpServletRequest req = (HttpServletRequest)request ;HttpServletResponse resp = (HttpServletResponse) response ;COOKIE[] COOKIEs = req.getCOOKIEs();resp.setCharacterEncoding("UTF-8");resp.setContentType("text/html;charset=UTF-8");HttpSession session = req.getSession();Object userInfo = session.getAttribute("userName");if(userInfo == null){ // 没登录if(COOKIEs != null){ // 有COOKIEfor(COOKIE COOKIE : COOKIEs){if("userInfo".equals(COOKIE.getName())){String[] value = COOKIE.getValue().split(":");String userName = value[0];String passwd = value[1];// 只有用户名与密码相同,则登录成功if(userName.equals(passwd)){// 创建COOKIE对象session.setAttribute("userName", userName + ",从filter登录成功");}else {session.setAttribute("userName", userName + ",从filter登录失败");}}}} else {// 这里应该跳转到登录页面}}chain.doFilter(request, response);}@Overridepublic void destroy() { }
}

 

3、index.jsp页面就展示登录用户用户名,如果没有登录就显示null


Hello !

<%&#61;session.getAttribute("userName")%>




注意&#xff1a;

      上面说过COOKIE是不能跨域的&#xff0c;通过特殊设置setDomain()可以做到夸同一个大域下的两个子域。例如&#xff0c;www.qiandu.com与mail.qiandu.com这是两个域&#xff0c;但是他们都是qiandu.com下的两个子域&#xff0c;则可以通过设置COOKIE.setDomain("qiandu.com")从而达到夸域。但是对于www.baidu.com与www.google.com就没得办法了。

 

8、测试COOKIE的单点登录

修改windows的hosts文件&#xff0c;添加如下内容&#xff1a;



 

测试步骤&#xff1a;

第一步&#xff1a;启动服务器&#xff0c;通过www.qiandu.com访问服务&#xff0c;显示登陆失败


 

第二步&#xff1a;通过get方式登录&#xff1a;http://www.qiandu.com/login?userName&#61;dgh&passwd&#61;dgh

 

第三步&#xff1a;登录http://mail.qiandu.com&#xff0c;发现第一次登陆mail.qiandu.com用户名密码就被COOKIE带过来了。

 

然后页面显示&#xff1a;

 

注意&#xff1a;为什么www.qiandu.com的COOKIE能带到mail.qiandu.com呢&#xff1f;我们从浏览器中查看COOKIE信息即可得知&#xff0c;域是www.qiandu.com与mail.qiandu.com的公共部分&#xff0c;所以浏览器认为&#xff0c;他们是一起的&#xff0c;COOKIE交流是安全的。而且我代码中写的是qiandu.com&#xff0c;浏览器自动在前面加了一个点

      

 

 

案例代码&#xff1a;http://download.csdn.net/detail/readiay/9654716

 

CAS统一认证的原理&#xff1a;http://blog.csdn.net/readiay/article/details/52856510

 


转载于:https://my.oschina.net/iyinghui/blog/1525306


推荐阅读
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • JavaScript简介及语言特点
    本文介绍了JavaScript的起源和发展历程,以及其在前端验证和服务器端开发中的应用。同时,还介绍了ECMAScript标准、DOM对象和BOM对象的作用及特点。最后,对JavaScript作为解释型语言和编译型语言的区别进行了说明。 ... [详细]
  • Request对象和Response对象request:(请求)当一个页面被请求时,Django就会创建一个包含本次请求原信息的HttpRequest对象。Djang ... [详细]
  • python之poc编写——sql篇
    文章目录sql注入漏洞漏扫单个网站基础sql扫描多个网站sql基础扫描时间盲注型扫描升阶版sq ... [详细]
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • Oracle10g备份导入的方法及注意事项
    本文介绍了使用Oracle10g进行备份导入的方法及相关注意事项,同时还介绍了2019年独角兽企业重金招聘Python工程师的标准。内容包括导出exp命令、删用户、创建数据库、授权等操作,以及导入imp命令的使用。详细介绍了导入时的参数设置,如full、ignore、buffer、commit、feedback等。转载来源于https://my.oschina.net/u/1767754/blog/377593。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • 分享css中提升优先级属性!important的用法总结
    web前端|css教程css!importantweb前端-css教程本文分享css中提升优先级属性!important的用法总结微信门店展示源码,vscode如何管理站点,ubu ... [详细]
  • CentOS7系统目录LINUX有四种基本文件系统类型普通文件:如文本文件、C语言元代码、SHELL脚本、二进制的可执行文件等,可用cat、less、 ... [详细]
  • 我只是互联网中的菜鸟一个,由于心血来潮也整了一个个人站,但在网络中游荡了大半个世纪,才发现给网站定位是多么的重要,只有好的运营模式及盈利模式,网站才能发展的更好,否则累死也赚不服务 ... [详细]
author-avatar
哀公家园_678
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有