web.xml配置cookie-config的secure为true时引发的血案

一个普通的不能再普通的登录场景:登录成功之后把用户信息放入session:

request.getSession().setAttribute("antiUser", user);

以后使用的时候再从session里面取出:

AntiUser antiUser = (AntiUser)request.getSession().getAttribute("antiUser");

本地运行没有任何问题,开玩笑,搞了那么多年java,这点功能还不是小意思?但是,接下来问题来了,当把项目部署到测试环境上之后,死活都从session里面取不到值,开始郁闷,没有网上说的ajax跨域问题,这到底是为什么呢?

查看f12开发者工具发现如下现象:

image.png

                                    图1

再次按f5刷新页面:

image.png

                                              图2

大家发现什么问题了吗?两个问题:

1.正常的情况下,对响应头Response Headers来说,只有我们第一次访问该网址时,响应头里面才会有Set-Cookie字段,之后不管你刷新多少次,响应头里面都不会有Set-Cookie字段了。对请求头Request Headers来说,第一次请求时,不发送Cookie字段,之后不管你刷新多少次,请求头都会发送Cookie字段,并且每次都有JSESSIONID这个键和值:

image.png

                                                       图3

这是正常的流程。

但是,上面每次刷新的时候都有Set-Cookie字段,请求头里没有Cookie字段。请求头不发送JSESSIONID,服务器就认为这是一个新的用户,就会为它分配一次session并把sessionid返回,就是上面Set-Cookie里的JSESSIONID。JSESSIONID的作用就是让后台java程序识别你是谁,通过JSESSIONID找到对应的session。也就是说,可以发现问题所在了:我登录成功之后,把用户信息放入了sessionid=123的session里,下一次请求却到sessionid=456的session里面去找,自然是获取不到呀。

2.问题发现之后,就要探究为什么会出现上面的问题,注意看我截取的Set-Cookie字段,后边有个“Secure; HttpOnly”,我在本地跑了个项目,设置了一个cookie,并没有这个东西啊:

image.png

难道是"Secure; HttpOnly"的原因导致了请求头Request Headers每次都不携带JSESSIONID,从而导致服务器认为是新用户而创建新的session?答案是正确的。

当在web.xml中做了如下配置

  <session-config>
    <session-timeout>240</session-timeout>
    <cookie-config>
    	<secure>true</secure>
    </cookie-config>
  </session-config>

之后,浏览器的响应头设置的Set-Cookie字段就如图1所示,会在JSESSIONID后加入“Secure; HttpOnly”,作用就是让请求头在http协议 下的Cookie字段不能携带JSESSIONID这个键,只能在https协议下才能携带,而我测试环境是http协议的,因此才导致了每次请求都创建一个session的问题。我们只需要配置

<secure>false</secure>

就可以了。记住:只需要在web.xml的cookie-config里面配置<secure>false</secure>,就可以解决sessionid每次请求都不同的问题,从而使session回归正常的使用方法。

说了这么多,归纳为一句话,<secure>true</secure>通过在Set-Cookie字段的JSESSIONID后加入“Secure; HttpOnly”的方式控制了请求头里面的Cookie不能在http协议下携带JSESSIONID这个键,而JSESSIONID这个键用于java后端识别客户端是谁,是否已经为它创建了session。

 

当然,我在java程序里面自己向浏览器加入的cookie也可以控制是否只能在https下才能被请求头的Cookie字段携带。

下面是普通的设置cookie和获取cookie的java代码:

package aaa;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/TestServlet")
public class TestServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
    public TestServlet() {
        super();
    }
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, 
	IOException {
		String flag = request.getParameter("flag");
		if ("get".equals(flag)) {//获取cookie
			Cookie[] cookies = request.getCookies();
			if (cookies!=null) {
				for(Cookie cookie:cookies){
					System.out.println(("key:"+cookie.getName()+",value:"+cookie.getValue()));
				}
			}
			System.out.println("sessionId:"+request.getSession().getId());
		}else if("set".equals(flag)){//设置cookie
			Cookie cookie1 = new Cookie("key1", "value1");  
            cookie1.setMaxAge(30);   //秒                  
            cookie1.setPath("/");
            response.addCookie(cookie1);  
		}
		
	}
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		this.doGet(request, response);
	}

}

访问“http://localhost:8080/test/TestServlet?flag=set”:

image.png

是没有问题的,访问“http://localhost:8080/test/TestServlet?flag=get”:

image.png

也可以取到。

修改设置cookie的代码加入cookie1.setSecure(true),如下:

image.png

重新启动项目,跟前边一样,访问“http://localhost:8080/test/TestServlet?flag=set”,结果如下:

image.png

我的天呢,果然多了个Secure。

我们再获取cookie呢,访问“http://localhost:8080/test/TestServlet?flag=get”:

image.png

我们可以看到,在请求头的Cookie字段里面并没有key1键。什么时候才有呢,通过https访问的时候才有。因此要想在http协议下能使用获取到key1,就不要给他设置setSecure(true)。

 

需要注意的是,自己设置的属性跟

  <cookie-config>

    <secure>false</secure>

    </cookie-config>

里面的secure是true还是false没有关系,secure是true还是false只控制Cookie字段里面有没有JSESSIONID键。

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值