Java会话管理:Cookie和Session

Author Avatar
stormjie 8月 07, 2018
  • 在其它设备中阅读本文章

http是无状态的,一次请求结束,连接断开,下次服务器再收到请求,它就不知道这个请求是哪个用户发过来的。当然它知道是哪个客户端地址发过来的,但是对于我们的应用来说,我们是靠用户来管理,而不是靠客户端。所以对我们的应用而言,它是需要有状态管理的,以便服务端能够准确的知道http请求是哪个用户发起的,从而判断他是否有权限继续这个请求。这个过程就是常说的会话管理。它也可以简单理解为一个用户从登录到退出应用的一段期间。

具体解释一下这个“无状态”:

  1. 协议对于事务处理没有记忆能力
  2. 对同一个url请求没有上下文关系
  3. 每次的请求都是独立的,它的执行情况和结果与前面的请求和之后的请求是无直接关系的,它不会受前面的请求应答情况直接影响,也不会直接影响后面的请求应答情况
  4. 服务器中没有保存客户端的状态,客户端必须每次带上自己的状态去请求服务器
  5. 人生若只如初见

    这有个具体的生活例子说明了无状态http的不便性:

当我们在一个购物网站上登陆自己的帐号后,我们便开始浏览商品,这时我们发现了心仪的商品,点进去打算看商品详情,发现竟然又要我们登陆帐号,为什么?因为无状态http请求无法保存我们用户信息,点击商品是一个请求,刚刚进入网站主页也是一个请求,这两个请求没有上下文联系,服务器无法判断这是同一个用户的请求,所以我们不得不再输入我们的账号密码,点击添加购物车,这也是一个请求,我们还是得输入帐号密码,还有其它商品操作,还有结算按钮。。。

没有会话管理技术会给我们生活带来多大不便从上个例子就可以略知一二,Java中我们有Cookie和Session来帮助我们解决这个麻烦。

一、Cookie

1.什么是Cookie

“Cookie是通过客户端保持状态的解决方案。从定义上来说,Cookie就是由服务器发给客户端的特殊信息,而这些信息以文本文件的方式存放在客户端,然后客户端每次向服务器发送请求的时候都会带上这些特殊的信息。让我们说得更具体一些:当用户使用浏览器访问一个支持Cookie的网站的时候,用户会提供包括用户名在内的个人信息并且提交至服务器;接着,服务器在向客户端回传相应的超文本的同时也会发回这些个人信息,当然这些信息并不是存放在HTTP响应体(Response Body)中的,而是存放于HTTP响应头(Response Header);当客户端浏览器接收到来自服务器的响应之后,浏览器会将这些信息存放在一个统一的位置,对于Windows操作系统而言,我们可以从: [系统盘]:\Documents and Settings[用户名]\Cookies目录中找到存储的Cookie;自此,客户端再向服务器发送请求的时候,都会把相应的Cookie再次发回至服务器。而这次,Cookie信息则存放在HTTP请求头(Request Header)了。 ”这是百度百科上关于Cookie的解释,说得很明了也很详细,下图是利用Cookie与服务器交流的简图:

2.Cookie的使用

如何使用Cookie?Java API关于Cookie提供了很多方法

方法 描述
Cookie(String name, String value) 实例化Cookie对象,传入Cookie名称和Cookie的值
public String getName() 取得Cookie的名字
public String getValue() 取得Cookie的值
public void setValue(String newValue) 设置Cookie的值
public void setMaxAge(int expiry) 设置Cookie的最大保存时间,即Cookie的有效期
public int getMaxAge() 获取Cookie的有效期
public void setPath(String uri) 设置Cookie的有效路径
public String getPath() 获取Cookie的有效路径
public void setDomain(String pattern) 设置Cookie的有效域
public String getDomain() 获取Cookie的有效域

已下是Cookie使用的一个例子,记录用户访问网站信息

public class CookieServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //设置服务器端以UTF-8编码进行输出
        response.setCharacterEncoding("UTF-8");
        //设置浏览器以UTF-8编码进行接收,解决中文乱码问题
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        //获取浏览器访问访问服务器时传递过来的cookie数组
        Cookie[] cookies = request.getCookies();
        //如果用户是第一次访问,那么得到的cookies将是null
        if (cookies!=null) {
            out.write("您上次访问的时间是:");
            for (int i = 0; i < cookies.length; i++) {
                Cookie cookie = cookies[i];
                if (cookie.getName().equals("lastAccessTime")) {
                    Long lastAccessTime =Long.parseLong(cookie.getValue());
                    Date date = new Date(lastAccessTime);
                    out.write(date.toLocaleString());
                }
            }
        }else {
            out.write("这是您第一次访问本站!");
        }

        //用户访问过之后重新设置用户的访问时间,存储到cookie中,然后发送到客户端浏览器
        Cookie cookie = new Cookie("lastAccessTime", System.currentTimeMillis()+"");//创建一个cookie,cookie的名字是lastAccessTime
        //将cookie对象添加到response对象中,这样服务器在输出response对象中的内容时就会把cookie也输出到客户端浏览器
        response.addCookie(cookie);
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}
3.Cookie的安全性

Cookie的目的是为用户带来方便,为网站带来增值,一般情况下不会造成严重的安全威胁。Cookie文件不能作为代码执行,也不会传送病毒,它为用户所专有并只能由创建它的服务器来读取。另外,浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为3KB,因此,Cookie不会塞满硬盘,更不会被用作”拒绝服务”攻击手段。

但是,Cookie作为用户身份的替代,其安全性有时决定了整个系统的安全性,Cookie的安全性问题不容忽视。

(1)Cookie欺骗

Cookie记录了用户的帐户ID、密码之类的信息,通常使用MD5方法加密后在网上传递。经过加密处理后的信息即使被网络上一些别有用心的人截获也看不懂。然而,现在存在的问题是,截获Cookie的人不需要知道这些字符串的含义,只要把别人的Cookie向服务器提交,并且能够通过验证,就可以冒充受害人的身份登陆网站,这种行为叫做Cookie欺骗。
非法用户通过Cookie欺骗获得相应的加密密钥,从而访问合法用户的所有个性化信息,包括用户的E-mail甚至帐户信息,对个人信息造成严重危害。
(2)Cookie截获
Cookie以纯文本的形式在浏览器和服务器之间传送,很容易被他人非法截获和利用。任何可以截获Web通信的人都可以读取Cookie。
Cookie被非法用户截获后,然后在其有效期内重放,则此非法用户将享有合法用户的权益。例如,对于在线阅读,非法用户可以不支付费用即可享受在线阅读电子杂志。

二、Session

1.什么是Session

Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。当程序需要为某个客户端的请求创建一个Session的时候,服务器首先检查这个客户端的请求里是否已包含了一个Session标识,称为SessionId,如果已包含一个SessionId则说明以前已经为此客户端创建过Session,服务器就按照SessionId把这个Session检索出来使用(如果检索不到,可能会新建一个),如果客户端请求不包含SessionId,则为此客户端创建一个Session并且生成一个与此Session相关联的SessionId,SessionId的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个SessionId将被在本次响应中返回给客户端保存。 保存这个SessionId的方式可以采用Cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发挥给服务器。

2.Session的使用
方法 描述
public String getId() 获取SessionID
public void setAttribute() 设置属性
public Object getAttribute() 获取属性
public void removeAttribute() 移除属性
public []String getAllAttributeNames() 获取所有的属性名
public int getMaxInactiveInterval() 获取最长到期时间
public void setMaxInactiveInterval() 设置最长到期事件
public void invalidate() 使该Session对象失效
public long getCreationTime() 获取创建时间
public long getLastAccessedTime() 获取上次访问时间

已下是Session使用的一个例子

//使用Session保存数据
public class Demo01 extends HttpServlet {
        public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            response.setContentType("text/html;charset=UTF-8");
            request.setCharacterEncoding("UTF-8");

            // 获取参数
            String username = request.getParameter("username");

            // 获取session对象
            HttpSession session = request.getSession();
            // 保存数据
            session.setAttribute("username", username);
            // 打印SessionID
            System.out.println(session.getId());
        }

        public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doGet(request, response);
        }
}

//测试获取Session域中的数据
public class Demo02 extends HttpServlet {
        public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            response.setContentType("text/html;charset=UTF-8");
            request.setCharacterEncoding("UTF-8");

            HttpSession session = request.getSession();
            String username = (String)session.getAttribute("username");
            // 响应到网页上
            response.getWriter().write(username + " " + session.getId());
        }

        public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doGet(request, response);
        }
}

三、Cookie和Session的区别

1.Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中; Cookie是把用户的数据写在用户本地浏览器上, 其他网站也可以扫描使用你的Cookie,容易泄露自己网站用户的隐私,而且一般浏览器对单个网站站点有Cookie数量与大小的限制,Cookie也是实现Session的一种方式。

2.Session 的运行依赖SessionId,而SessionId 是存在Cookie中的,也就是说,如果浏览器禁用了Cookie ,同时 Session 也会失效(但是可以通过其它方式实现,比如在 url 中传递 SessionId) 。

3.一般情况,登录信息等重要信息存储在Session中,其他信息存储在Cookie中 。