Java Web —— Session 和 cookie 保存登录信息

session 与 cookie

cookie 与 session 应用于互联网中的一项基本技术——会话(客户端与服务端的交互)跟踪技术,用来跟踪用户的整个会话。简单来说,cookie 是通过在客户端记录信息确定用户身份的,而 session 则通过在服务器端记录信息确定用户身份。

1、用户登陆过程中的 cookie 和 session 保持过程:
在这里插入图片描述

假设没有设置其他 cookie 情况下,A在第一次访问 B 时,B 会为 A 创建一个属于 A 的 session,并在 B 响应 A 时通过 cookie 保存 sessionid 响应给 A。这样 A 在第二次访问 B 的时候,A 带着 cookie(此时里面有 sessionid)请求 B,B 收到请求后会通过 cookie 的 sessionid 辨识出属于 A 的 session,这就是整个过程。

2、两者对比

(1)应用场景

Cookie 的典型应用场景是Remember Me服务,即用户的账户信息通过 cookie 的形式保存在客户端,当用户再次请求匹配的URL的时候,账户信息会被传送到服务端,交由相应的程序完成自动登录等功能。当然也可以保存一些客户端信息,比如页面布局以及搜索历史等等。
Session 的典型应用场景是用户登录某网站之后,将其登录信息放入session,在以后的每次请求中查询相应的登录信息以确保该用户合法。当然还是有购物车等等经典场景;

(2)安全性

cookie 将信息保存在客户端,如果不进行加密的话,无疑会暴露一些隐私信息,安全性很差,一般情况下敏感信息是经过加密后存储在 cookie 中,但很容易就会被窃取。而 session 只会将信息存储在服务端,如果存储在文件或数据库中,也有被窃取的可能,只是可能性比 cookie 小了太多。
Session 安全性方面比较突出的是存在会话劫持的问题,这是一种安全威胁。
总体来讲,session 的安全性要高于 cookie

(3)性能

Cookie 存储在客户端,消耗的是客户端的 I/O 和内存,而 session 存储在服务端,消耗的是服务端的资源。但是 session 对服务器造成的压力比较集中,而 cookie 很好地分散了资源消耗,就这点来说,cookie 是要优于 session的;

(4)时效性

Cookie 可以通过设置有效期使其较长时间内存在于客户端,而 session 一般只有比较短的有效期(用户主动销毁 session 或关闭浏览器后引发超时)

(5)其他

Cookie 的处理在开发中没有 session 方便。而且 cookie 在客户端是有数量和大小的限制的,而 session 的大小却只以硬件为限制,能存储的数据无疑大了太多。

一、session

HTTP 协议是非连接性的,取完当前浏览器的内容,然后关闭浏览器后,链接就断开了,而没有任何机制去记录取出后的信息。而当需要访问同一个网站的另外一个页面时(就好比如在第一个页面选择购买的商品后,跳转到第二个页面去进行付款)就读不信息出来了。所以必须要有一种机制保持会话状态。
当访问服务器否个网页的时候,会在服务器端的内存里开辟一块内存,这块内存就叫做 session。这个 session 是跟浏览器关联在一起的,只允许当前这个 session 对应的浏览器访问,就算是在同一个机器上新启的浏览器也是无法访问的。而另外一个浏览器也需要记录 session 的话,就会再启一个属于自己的 session。
当访问一个页面的时候给浏览器创建一个独一无二的号码,也给同时创建的 session 赋予同样的号码。这样就可以在打开同一个网站的第二个页面时获取到第一个页面中 session 保留下来的对应信息(理解:当访问第二个页面时将号码同时传递到第二个页面。找到对应的 session)。这个号码也叫 sessionID,session 的 ID 号码,session 的独一无二号码。

1、HttpSession

javax.servlet.http.HttpSession 接口表示一个会话,我们可以把一个会话内需要共享的数据保存到 HttSession 对象中!
当需要为应用端建立一个 session 时,servlet 容器就创建了一个 HttpSession 对象,其中存储了和该 session 相关的信息。所以在一个 servlet 中有多少个不同应用连接,就会有多少个 HttpSession 对象。
HttpServletRequest、HttpServletResponse、ServletContext 和 HttpSession 都是 Servlet 中可以使用的域对象。

1)HttpServletRequest:一个请求创建一个 request 对象,所以在同一个请求中可以共享 request,例如一个请求从 AServlet 转发到 BServlet,那么 AServlet 和 BServlet 可以共享 request 域中的数据;
2)ServletContext:一个应用只创建一个 ServletContext 对象,在 ServletContext 中的数据可以在整个应用中共享,只要不启动服务器,那么 ServletContext 中的数据就可以共享;
3)HttpSession:一个会话创建一个 HttpSession 对象,同一会话中的多个请求中可以共享 session 中的数据

2、session 的工作流程

(1)创建 session
用户第一次请求服务器时,服务器就会为该用户分配一个 session 对象,创建的同时为这个 session 指定唯一的 sessionId,session 对象可以通过调用 HttpServletRequest 的 getSession(false) 方法获得;

// 当参数为空或者true时,获得session,若没有则新建;当参数为false时,获得session,若没有也不会新建
HttpSession session = request.getSession(false);

tomcat 的 ManagerBase 类提供创建 sessionId 的方法:随机数 + 时间 + jvmid

(2)服务器返回 sessionId 返回给客户端
服务器端将生成的 sessionId 自动返回给客户端,客户端收到 sessionId 会将它保存在 cookie 中,使得客户端与服务器的 session 建立一一对应的关系,当客户端再次访问服务端时会通过 Request Header 的 cookie 带上 sessionId
在这里插入图片描述

该过程由服务器和浏览器自动完成,不需要手动进行

(3) 客户端携带 sessionId 请求
当服务端再次接收到来自客户端的请求时,会先去检查是否存在 sessionId。不存在就新建一个 sessionId,然后重复1、2的流程;如果存在就去遍历服务端的 session 文件,找到与这个 sessionId 相对应的文件,文件中的键值便是 sessionId,当客户端继续访问服务器端的其它资源时,服务器不再为该客户分配新的 session 对象,直到客户端浏览器关闭、超时或调用 session 的 invalidate()方法使其失效,客户端与服务器的会话结束;
(4)此后的请求都会交换这个 sessionId,进行有状态的会话;
(5)当客户重新打开浏览器访问网站时,服务器会重新为客户分配一个 session 对象,并重新分配 sessionID

3、session 的生命周期

(1)session 何时生效:

session 在用户访问第一次访问服务器时创建,需要注意只有访问 JSP、Servlet 等程序时才会创建 Session;只访问 HTML、IMAGE 等静态资源并不会创建 Session,可调用 request.getSession(true) 强制生成 Session。

(2)session 何时失效:
1)服务器会把长时间没有活动的 Session 从服务器内存中清除,此时 Session 便失效。

Tomcat 中 Session 的默认失效时间为20分钟。从 session 不活动的时候开始计算,如果 session 一直活动,session 就总不会过期。从该 Session 未被访问开始计时, 一旦 Session 被访问则计时清 0;

2)调用 Session 的 invalidate 方法

HttpSession session = request.getSession();
session.invalidate();    // 注销该 request 的所有 session 

3)设置 session 的失效时间

● web.xml中

<session-config> 
	<session-timeout>30</session-timeout>
</session-config> 

● 在程序中手动设置

session.setMaxInactiveInterval(30 * 60);    // 设置单位为秒,设置为-1永不过期 
request.getSession().setMaxInactiveInterval(-1);    // 永不过期 

● tomcat 也可以修改 session 过期时间,在 server.xml 中定义 context 时采用如下定义:

<Context path="/livsorder" docBase="/home/httpd/html/livsorder"
defaultSessionTimeOut="3600" isWARExpanded="true"   
isWARValidated="false" isInvokerEnabled="true"
isWorkDirPersistent="false"/> 

注意:关闭浏览器,sessionId 会失效;但是 session 不会失效

4、session 的存储

在 session 被创建之后,就可以调用 session 相关的方法往 session 中增加内容,而这些 session 的内容会存储在服务器的内存中,也可以持久化到 file、数据库、memcache 和 redis等。客户端只保存 sessionId 到 cookie 中,而不会保存 session 的其他内容,session 销毁只能通过 invalidate 或超时,关闭浏览器并不会清除 session。

session 存储的问题

(1)内存不足:大多数 Web 框架会把 session 数据存放到内存中。如果你的 Web 应用用户量不大的话,这也不成问题。但如果你的用户数比较大的话,就可能发生一个事情 — 内存不够用。内存容量是非常宝贵的,假设每个用户的 session 数据是 100K,1万个用户就会大概占用 1G 的存储空间,如果你的 session 数据清理机制也恰巧比较慢的话,内存非常容易被占满。

这就需要你在设计比较大并发量的站点时,要考虑 Session 的存储方式,比如把它们保存到硬盘文件系统中,或者数据库中。 所以你在开发一个 Web 应用的时候,如果你的用户量很大,你需要有这个意识。

(2)服务器重启 session 会被清空:另外 Session 放到内存中还有一个弊端,如果你的 Web 服务器发生重启,那么所有的 session 状态都会被清空,会在一定程度上影响用户体验。

5、Session 的常用方法

session 的方法都在 javax.servlet.http.HttpSession 包下。

1)HttpSession request.getSesssion():如果当前会话已经有了 session 对象那么直接返回,如果当前会话还不存在会话,那么创建新的 session 并返回;
2)HttpSession request.getSession(boolean):当参数为 true 时,与 requeset.getSession() 相同。如果参数为 false,那么如果当前会话中存在 session 则返回,不存在返回 null(不回创建新的 session);
3) public void setAttribute(String name,String value):设定指定名字的属性的值,并将它添加到 session 会话范围内,如果这个属性是会话范围内存在,则更改该属性的值;
4) public Object getAttribute(String name):在会话范围内获取指定名字的属性的值,返回值类型为 object,如果该属性不存在,则返回 null;
5)public void removeAttribute(String name):删除指定名字的 session 属性,若该属性不存在,则出现异常;
6) public void invalidate():使 session 失效。可以立即使当前会话失效,原来会话中存储的所有对象都不能再被访问;
7) public String getId( ):获取当前的会话 ID。每个会话在服务器端都存在一个唯一的标示 sessionID,session 对象发送到浏览器的唯一数据就是 sessionID,它一般存储在 cookie 中;
8) public void setMaxInactiveInterval(int interval): 设置会话的最大持续时间,单位是秒,负数表明会话永不失效;
9)public int getMaxInActiveInterval():获取会话的最大持续时间,使用时候需要一些处理;
10) public boolean isNew():是否是新的 Session,一般在第一次访问的时候出现 ;
11) getCreationTime():当前 session 创建的时间;
12) getLastAccessedTime():最近的一次访问这个 session 的时间;
13) getRrquestedSessionid: 跟随上个网页 cookies 或者 URL 传过来的 session;
14) isRequestedSessionIdFromCookie():是否通过 Cookies 传过来的;
15) isRequestedSessionIdFromURL():是否通过重写 URL 传过来的;
16) isRequestedSessionIdValid():是不是有效的 sessionID;

6、session 的应用场景

(1)通过session累计用户数据

例如,一个未登录用户访问了京东网站,这个时候京东对其下发了一个 cookie,假设 cookie 的名字叫做 abc,那这条记录就是 abc=001,同时京东的后台也生成了一个 sessionId, 它的值也为 001, 001 这个客户在 2 点、 3 点、 4 点分别添加了三件商品到购物车,这样后台也记录了 sessionId 为 001的用户的购物车里面已经有三件商品,并且只要每次客户端 cookie 带上来的值里面包含sessionId,后台都能够展示相应的数据,如果这个时候,在浏览器里面清空 cookie,cookie 数据消失之后,后台和客户端无法建立对应关系,购物车的数据就会失效了。

(2)通过 session 实现单点登录

一个用户帐号成功登录后,在该次 session 还未失效之前,不能在其他机器上登录同一个帐号。登录后将用户信息保存到 session 中,如果此时在另外一台机器上一个相同的帐号请求登录,通过遍历(遍历的意思就是将所有 session 都查看一遍)Web 服务器中所有 session 并判断其中是否包含同样的用户信息,如果有,在另一台机器上是不能登录该帐号的。

7、SessionID 传输安全

假如 SessionID 是基于 HTTP 协议传输的,因为是明文传输,那么它就可能被中间的路由器劫持。 攻击者得到 SessionID 后,把它带到自己的请求中,就能够进入你的账户。

所以一些 Web 框架还提供了 Session 的一些安全保护,比如间隔时间内动态刷新 SessionID,加上 Token 等。但这些也无法完全保证不被中间人看到。 其实从这个角度也间接体现了为什么 HTTPS 这么重要。

二、Cookie

cookie 是服务器传给客户端的体积很小的纯文本文件。客户端请求服务器,如果服务器需要记录该用户状态,就向客户端浏览器发一个 cookie。客户端浏览器会把 cookie 保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该 cookie一同提交给服务器,服务器检查该 cookie,以此来辨认用户状态。

1、cookie 的内容

主要包括:名字、值、过期时间、路径和域。
在这里插入图片描述
路径与域一起构成 cookie 的作用范围。如某 cookie 的 domain 为 “baidu.com”, path 为 “/ ”,若请求的URL(URL 可以是js/html/img/css资源请求,但不包括 XHR 请求)的域名是“baidu.com”或其子域如“api.baidu.com”、“dev.api.baidu.com”,且 URL 的路径是“/ ”或子路径“/home”、“/home/login”,则浏览器会将此 cookie 添加到该请求的 cookie 头部中。所以domain和path2个选项共同决定了cookie何时被浏览器自动添加到请求头部中发送出去。如果没有设置这两个选项,则会使用默认值。domain的默认值为设置该cookie的网页所在的域名,path默认值为设置该cookie的网页所在的目录。
● 过期时间:对于会话 cookie,如果不设置过期时间,表示这个 cookie 的生命期为浏览器的会话期间,关闭浏览器窗口,cookie 就消失了,会话 cookie 一般保存在内存里对于持久 cookie,设置了过期时间,浏览器会把 cookie 保存在硬盘上,存储在硬盘上的 cookie 会在不同的浏览器进程间共享
● 名字:就是给 cookie 起一个名字。
● 值:cookie 中记录的信息内容。

在 chrome 浏览器中一个网站,进入开发者模式,点击 Application 栏 -> 选择 cookies,我们会看到如下图所示的界面:
在这里插入图片描述
左边栏 Cookies 下方会列举当前网页中设置过 cookie 的域都有哪些。上图中只有一个域,即 “ppsc.sankuai.com”。而右侧区域显示的就是某个域下具体的 cookie 列表,对应上图就是 “ppsc.sankuai.com” 域下设置的 4 个 cookie。

2、cookie 的生成与存储

(1)生成

1) cookie 在服务端生成的构造函数如下:

Cookie(String, String)	// 使用指定的 Cookie 和 Name 初始化 Value 类的新实例。
Cookie(String, String, String)	// 使用指定的 Name、Value 和 Path 初始化 Cookie 类的新实例。
Cookie(String, String, String, String)	// 使用指定的 Name、Value、Path 和 Domain 初始化 Cookie 类的新实例。

2) 将 cookie 放到响应 response 中的方法如下:

response.addCookie(cookie);

3) 服务器端将生成的 cookie 通过 Response Header 的 set-cookie 返回给客户端

无论使用何种服务端技术,只要发送回的 HTTP 响应中包含如下形式的头,则视为服务器要求设置一个 cookie:
在这里插入图片描述
支持 cookie 的浏览器都会对此作出反应,即创建 cookie 文件并保存(也可能是内存cookie)。

(2)存储

存储 cookie 是浏览器提供的功能。cookie 是存储在浏览器中的纯文本,浏览器的安装目录下会专门有一个 cookie 文件夹来存放各个域下设置的 cookie

(3)使用

1) 当网页要发 http 请求时,浏览器会先检查是否有相应的 cookie,有则自动添加在 request header 中的 cookie 字段中。这些是浏览器自动帮我们做的,而且每一次 http 请求浏览器都会自动帮我们做
在这里插入图片描述
2) 什么样的数据适合存储在 cookie 中非常重要。如果这些数据并不是每个请求都需要发给服务端的数据,浏览器这设置自动处理无疑增加了网络开销;但如果这些数据是每个请求都需要发给服务端的数据(比如身份认证信息),浏览器这设置自动处理就大大免去了重复添加操作。所以对于那设置“每次请求都要携带的信息(最典型的就是身份认证信息)”就特别适合放在 cookie 中,其他类型的数据就不适合了。

3) cookie 的使用是由浏览器按照一定的原则在后台自动发送给服务器的。浏览器检查所有存储的 cookie,如果某个 cookie 所声明的作用范围大于等于将要请求的资源所在的位置,则把该 cookie 附在请求资源的HTTP请求头上发送给服务器

用户以后在每次发出请求时,浏览器都要判断当前所有的 cookie 中有没有没失效(根据expires属性判断)并且匹配了 path 属性的 cookie 信息,如果有的话,会以下面的形式加入到请求头中发回服务端

Cookie: name="zj"; Path="/linkage" 

服务端的动态脚本会对其进行分析,并做出相应的处理,当然也可以选择直接忽略。

3、httpOnly

这个选项用来设置 cookie 是否能通过 js 去访问。默认情况下,cookie 不会带 httpOnly选项(即为空),即客户端是可以通过js代码去访问(包括读取、修改、删除等)这个 cookie 的。当 cookie 带 httpOnly 选项时,客户端则无法通过 js 代码去访问(包括读取、修改、删除等)这个cookie。
在客户端是不能通过 js 代码去设置一个 httpOnly 类型的 cookie 的,这种类型的 cookie 只能通过服务端来设置。 那我们在页面中怎么知道哪些 cookie 是 httpOnly 类型的呢?看下图:
在这里插入图片描述凡是 httpOnly 类型的 cookie,其 HTTP 一列都会打上√,如上图中的 PA_VTIME。你通过 document.cookie 是不能获取的,也不能修改 PA_VTIME 的。

为什么我们要限制客户端去访问 cookie?其实这样做是为了保障安全。

会话 cookie 中缺少 HttpOnly 属性会导致攻击者可以通过程序( JS 脚本、Applet 等)获取到用户的 cookie 信息,造成用户 cookie 信息泄露,增加攻击者的跨站脚本攻击威胁,如 ASP.NET 会话 ID 或 Forms 身份验证票证,攻击者可以重播窃取的 Cookie,以便伪装成用户或获取敏感信息,进行跨站脚本攻击等。
如果在 Cookie 中设置 HttpOnly 属性为 true,兼容浏览器接收到 HttpOnly cookie,那么客户端通过程序( JS 脚本、Applet 等)将无法读取到 Cookie 信息,这将有助于缓解跨站点脚本威胁。

设置 httponly 属性

通过 Cookie 类的以下方法可以设置 httponly 属性:

setHttpOnly(boolean httpOnly) 

4、设置 cookie

cookie 既可以由服务端来设置,也可以由客户端来设置。

(1)服务端设置 cookie

不管你是请求一个资源文件(如 html/js/css/图片),还是发送一个 ajax 请求,服务端都会返回 response。而 response header 中有一项叫 set-cookie,是服务端专门用来设置 cookie 的一个 set-Cookie 字段只能设置一个 cookie,当你要想设置多个 cookie,需要添加同样多的 set-Cookie 字段。如下图所示,服务端返回的 response header 中有5个 set-cookie 字段,每个字段对应一个 cookie(注意不能将多个 cookie 放在一个set-cookie字段中),set-cookie 字段的值就是普通的字符串,每个 cookie 还设置了相关属性选项。

服务端增删改 cookie 的方法:

1)添加 cookie 示例
获取客户端的 Cookie 时,只能获取 name 与 value 属性,其它属性都不会被提交

Cookie c = new Cookie("username","peter");// 新建一个 Cookie 对象
c.setMaxAge(24*60*60);                    // 设置过期时间1天,以秒为单位
response.addCookie(c);                    // 保存 cookie 到客户端 

2)删除 cookie 示例
如果要删除某个 Cookie,则只需要新建一个同名的 Cookie,并将maxAge设置为 0,并覆盖原来的 Cookie 即可。

Cookie c = new Cookie("username","peter");     // 新建同名 Cookie
cookie.setMaxAge(0);                           // 设置生命周期为 0,表示将要删除
response.addCookie(c);                    // 执行添加后就从 response 里删除了

3)修改 cookie 示例
HttpServletResponse 提供的 Cookie 操作只有一个 addCookie(Cookie cookie),所以想要修改 Cookie只能使用一个同名的 Cookie 来覆盖原先的Cookie

Cookie c = new Cookie("username","joker"); // 新建Cookie
cookie.setMaxAge(24*60*60);                    // 设置生命周期
response.addCookie(c);                    //执行添加后就从response里覆盖修改了

注意:修改、删除 Cookie 时,新建的 Cookie 除 value、maxAge 之外的所有属性,例如name、path、domain等,都要与原Cookie完全一样。否则,浏览器将视为两个不同的Cookie而不会覆盖之前的Cookie,从而导致修改、删除失败

(2)客户端设置 cookie

在网页即客户端中我们也可以通过 js 代码来设置 cookie。如我当前打开的网址为http://dxw.st.sankuai.com/mp/,在控制台中我们执行了下面代码:

document.cookie="age=12; expires=Thu, 26 Feb 2116 11:50:25 GMT; domain=sankuai.com; path=/";

查看浏览器 cookie 面板,如下图所示,新的 cookie 设置成功了,而且属性选项 domain、path、expires都变成了设定的值。

客户端可以设置 cookie 的下列选项:expires、domain、path、secure(有条件:只有在 https 协议的网页中,客户端设置 secure 类型的 cookie 才能成功),但无法设置 HttpOnly 选项。

设置多个 cookie 的方法就在重复执行 document.cookie = “key=name”,如下:

document.cookie = "name=Jonh";
document.cookie = "age=12";
document.cookie = "class=111";

若使用如下代码设置多个 cookie :

document.cookie = "name=Jonh; age=12; class=111"; 

会发现这样写只是添加了第一个cookie“name=John”,后面的所有cookie都没有添加成功。

5、Cookie 类的各方法详解

Cookie 类在 javax.servlet.http.Cookie 包中
在这里插入图片描述对应的 getter 方法同上。
如果 cookie 值为 Unicode 字符,需要为字符编码。如果cookie值为二进制数据,则需要使用 BASE64 编码。

cookie 的 setPath() 和 setDomain() 方法:

默认情况下cookie只能在一个应用中共享,即一个cookie只能由创建它的应用获得

● 设置同一服务器内的cookie使用范围用setPath; c.setPath(“/”),使同一服务器内所有应用都可访问到该Cookie:

Cookie c = new Cookie("name","peter");  
c.setMaxAge(24*60*60);
c.setPath("/");    //同一服务器内所有应用都可访问到该Cookie  
response.addCookie(c);    //保存cookie到客户端 

6、cookie 的域名和跨域

Cookie 是不可以跨域名的,如域名 www.google.com 颁发的 Cookie 不会被提交到域名 www.baidu.com 去。这是由 Cookie 的隐私安全机制决定的。

正常情况下,同一个一级域名下的两个二级域名也不能交互使用 Cookie,比如 test1.mcrwayfun.com 和 test2.mcrwayfun.com,因为二者的域名不严格相同。

如果想要 mcrwayfun.com 名下的二级域名都可以使用该 Cookie,需要设置 Cookie 的 domain 参数为一级域名 .mcrwayfun.com,这样使用 test1.mcrwayfun.com 和 test2.mcrwayfun.com 就能访问同一个cookie。

Cookie cookie = new Cookie("name","peter"); // 新建Cookie
cookie.setDomain(".mcrwayfun.com");               // 设置域名
cookie.setPath("/");                        // 设置路径
cookie.setMaxAge(Integer.MAX_VALUE);        // 设置有效期为永久
response.addCookie(cookie);                 // 输出到客户端 

注意:domain 参数必须以点(“.”)开始
另外,name 相同但 domain 不同的两个 Cookie 是两个不同的 Cookie。如果想要两个域名完全不同的网站共有Cookie,可以生成两个 name 相同的 Cookie,domain 属性分别为两个域名

7、使用 cookie 记住密码

方案1:

直接把用户名与密码都保持到Cookie中,下次访问时检查Cookie中的用户名与密码,与数据库比较。这是一种比较危险的选择,一般不把密码等重要信息保存到Cookie中。

方案2:

把密码加密后保存到 Cookie 中,下次访问时解密并与数据库比较。这种方案略微安全一些。如果不希望保存密码,还可以把登录的时间戳保存到 Cookie 与数据库中,到时只验证用户名与登录时间戳就可以了。

方案3:

实现方式是把账号按照一定的规则(密钥)加密后,连同账号一块保存到Cookie中。下次访问时只需要判断账号的加密规则是否相同即可。

加密:

String userName = request.getParameter("userName");		// 获取用户名
Md5Hash psw = new Md5Hash(userName, "peter.com", 2);	//以peter.com为密钥加密

//将用户名添加进cookie并发送给客户端
Cookie userCookie = new Cookie("userName",userName);
userCookie.setMaxAge(7*24*60*60);
response.addCookie(userCookie);

//将密钥生成的密文加进cookie并发送给客户端
Cookie c = new Cookie("key",psw.toString());
c.setMaxAge(7*24*60*60);
response.addCookie(c);

解密:

String usreName = null;
String key = null;
Cookie[] cookie = request.getCookies();
if(cookie !=null){              
    for(Cookie c:cookie){  // 遍历Cookie
       if("userName".equals(c.getName()) 
           userName = c.getValue();      
       if("key".equals(c.getName()) 
           key= cookie.getValue();       
    }
}
if(userName != null && key != null){   
    String secrect = new Md5Hash(userName, "peter.com", 2);
    if(key.equals(secrect )){//加密规则正确,说明已经登录
        //...
        //....省略后续处理
    }
}

将密码加密后存进cookie后,当我们下次访问登录页时,密码框里的密码将不是用户真正的密码。

8、解决 cookie 里中文乱码问题

Cookie 中要保存中文只能编码,一般使用 UTF-8编码即可,不推荐使用GBK等中文编码,因为浏览器不一定支持,而且 JavaScript 也不支持 GBK 编码。

Cookie 不仅可以使用 ASCII 字符与 Unicode 字符,还可以使用二进制数据。例如在 Cookie 中使用数字证书,提供安全度。使用二进制数据时也需要进行编码(如用BASE64编码保存二进制图片)。由于浏览器每次请求都会带着 Cookie,因此 Cookie 内容不宜过多,所以一般不会在 Cookie 中存储二进制的内容。

9、cookie 应用场景

(1)判断注册用户是否已经登录网站

用户可能会得到提示,是否在下一次进入此网站时保留用户信息以便简化登录流程。

(2)根据用户的爱好定制内容

网站创建包含用户浏览内容的cookies,在用户下次访问时,网站根据用户的情况对显示的内容进行调整,将用户感兴趣的内容放在前列。

(3)实现永久登录

如果用户是在自己家的电脑上上网,登录时就可以记住他的登录信息,下次访问时不需要再次登录,直接访问即可。

(4)实现自动登录

当用户注册网站后,就会收到一个惟一用户ID的cookie。用户再次连接时,这个用户ID会自动返回,服务器对它进行检查,确定它是否是注册用户且选择了自动登录,从而使用户无需给出明确的用户名和密码,就可以访问服务器上的资源。

(5)使用 cookie 记录各个用户的访问计数

获取cookie数组中专门用于统计用户访问次数的cookie的值,将值加1并将最新cookie输出。

(6)使用 cookie 记住用户名与用户密码

用户勾选了“自动登录”,就把用户名和密码的信息放到cookie中。同时可设置有效期。

(7)用 cookie 实现新手大礼包等弹窗功能

同理,将新手大礼包弹窗逻辑写入到cookie中,并设置相应的有效期。比如在有效期内只弹出一次该弹窗,超过有效期登录后再次弹出弹窗。

三、Session 与 Cookie 使用示例

设计思路

首先,用户登录成功后保存用户登陆的用户名到 Cookie 和 session,同时设置 Cookie 的有效时间,在下次用户想免输入登陆时,直接判断 Cookie 中的用户名和 session 中的是否一致,如果一致则直接登陆不需要输入,否则需要重新输入用户名和密码。


版权声明:本文为IT__learning原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。