解决session老是变化:Web App设置响应cookie + Nginx反向代理之Cookie设置

问题:直接访问Web应用,Session不变化,可以取到登录后放入session的User数据; 通过访问Nginx代理服务器来访问应用,Session总是变化(请求jessionid没来自cookie),取不到放入session的user数据,总是需要从新登录。

参考了:
《精通Nginx 第二版》4.3 带有Cookie的遗留应用程序,https://www.sohu.com/a/233790408_468627 ,https://blog.csdn.net/qiqingjin/article/details/51760343

解决session老是变化:Web App设置响应cookie,cookie中存放jsessionid + Nginx反向代理进行Cookie设置。

你可能会发现,自己需要在一个共同的端点服务器后放置多个遗留应用程序。在它们是唯一应用程序的情况下, 这些遗留应用程序是直接与客户端对话的。
它们在自己的域设置了cookies,并且假设它们总是通过几JRL 到达。如果在这些服务器之前放置一个新的端点, 这些假设将不再成立。
下面的配置将重写cookie 的域和路径,以便匹配新的应用端点。
1

1.应用代码

public class LoginFilter extends OncePerRequestFilter {
private static Logger LOGGER = Logger.getLogger(LoginFilter.class);

@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException,
IOException {

if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
throw new ServletException(“OncePerRequestFilter just supports HTTP requests”);
}
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;

LOGGER.info(“remote addr is: ” + httpRequest.getRemoteAddr());//getRemoteAddr(): Returns the Internet Protocol (IP) address of the client or last proxy that sent the request.
LOGGER.info(“X-Real-IP is: ” + httpRequest.getHeader(“X-Real-IP”));
LOGGER.info(“X-Forwarded-For: ” + httpRequest.getHeader(“X-Forwarded-For”));
Enumeration parameterNames = httpRequest.getParameterNames();
while (parameterNames.hasMoreElements()) {
LOGGER.info(“Parameter Name: ” + parameterNames.nextElement().toString());
}
LOGGER.info(“Header Host: ” + httpRequest.getHeader(“Host”));

HttpSession session = httpRequest.getSession();
SysUser user = (SysUser) session.getAttribute(“user”);
String servletPath = httpRequest.getServletPath();
if (null == user
&& (!”/gotoLogin”.equals(servletPath) && !”/login”.equals(servletPath))) {
     LOGGER.info(“—-null == user,servletPath: ” + servletPath + ” —————“);
      httpResponse.sendRedirect(“/gotoLogin”);
} else {
filterChain.doFilter(httpRequest, httpResponse);
}

        }
}

@Controller
public class LoginController {
private static Logger LOGGER = Logger.getLogger(LoginController.class);

@RequestMapping(“/login”)
public void login(HttpServletRequest request, HttpServletResponse response)
throws IOException {

LOGGER.info(“request /login”);
String username = request.getParameter(“username”);
String password = request.getParameter(“password”);

 // 请求转发的方式:
//request.getRequestDispatcher(“success.jsp”).forward(request,response);
//<jsp:forward page=”success.jsp” />
if (“admin”.equalsIgnoreCase(username) && “123456”.equals(password)) {
SysUser user = new SysUser(1L, username, password,
“lvzhongqian@huawei.com”, new Date());
LOGGER.info(“——login successed !——“);
HttpSession session = request.getSession();
session.setAttribute(“user”, user);
response.sendRedirect(“/dicts”);
} else {
response.sendRedirect(“/gotoLogin”);
}

}

@RequestMapping(value = { “”, “/gotoLogin” })
public ModelAndView gotoLogin() {
ModelAndView mv = new ModelAndView(“login”);
return mv;
}

}

2.直接访问应用服务器的时候:

2

请求包含了jessionid;响应没有设置cookie,没有给响应设置jessionid(cookie)信息。应用服务器,也并没有给httpResponse设置响应cookie。

3.访问反向代理服务器的方式访问应用:

3

这个响应cookie是Nginx反向代理服务器设置的。

4.修改应用程序代码,设置httpResonse响应cookie

相关知识:服务器端的发送与解析

Cookie的来源
由于HTTP协议是无状态的,而服务器端的业务必须是要有状态的。Cookie诞生的最初目的是为了存储web中的状态信息,以方便服务器端使用。比如判断用户是否是第一次访问网站。目前最新的规范是RFC 6265,它是一个由浏览器服务器共同协作实现的规范。
Cookie的处理分为:
服务器向客户端发送cookie;
浏览器将cookie保存;
之后每次http请求浏览器都会将cookie发送给服务器端。

发送cookie
服务器端像客户端发送Cookie是通过HTTP响应报文实现的,在Set-Cookie中设置需要像客户端发送的cookie,cookie格式如下:
Set-Cookie: “name=value;domain=.domain.com;path=/;expires=Sat, 11 Jun 2016 11:29:42 GMT;HttpOnly;secure”
其中name=value是必选项,其它都是可选项。

Cookie的主要构成如下:
name:一个唯一确定的cookie名称。通常来讲cookie的名称是不区分大小写的。
value:存储在cookie中的字符串值。最好为cookie的name和value进行url编码
domain:cookie对于哪个域是有效的。所有向该域发送的请求中都会包含这个cookie信息。这个值可以包含子域(如:yq.aliyun.com),也可以不包含它(如:.aliyun.com,则对于aliyun.com的所有子域都有效).
path: 表示这个cookie影响到的路径,浏览器跟会根据这项配置,像指定域中匹配的路径发送cookie。
expires:失效时间,表示cookie何时应该被删除的时间戳(也就是,何时应该停止向服务器发送这个cookie)。如果不设置这个时间戳,浏览器会在页面关闭时即将删除所有cookie;不过也可以自己设置删除时间。这个值是GMT时间格式,如果客户端和服务器端时间不一致,使用expires就会存在偏差。
max-age: 与expires作用相同,用来告诉浏览器此cookie多久过期(单位是秒),而不是一个固定的时间点。正常情况下,max-age的优先级高于expires。
HttpOnly: 告知浏览器不允许通过脚本document.cookie去更改这个值,同样这个值在document.cookie中也不可见。但在http请求张仍然会携带这个cookie。注意这个值虽然在脚本中不可获取,但仍然在浏览器安装目录中以文件形式存在。这项设置通常在服务器端设置。
secure: 安全标志,指定后,只有在使用SSL链接时候才能发送到服务器,如果是http链接则不会传递该信息。就算设置了secure 属性也并不代表他人不能看到你机器本地保存的 cookie 信息,所以不要把重要信息放cookie就对了

需要注意的是,如果给cookie设置一个过去的时间,浏览器会立即删除该cookie;此外domain项必须有两个点,因此不能设置为localhost:
something that wasn’t made clear to me here and totally confused me for a while was that domain names must contain at least two dots (.),hence ‘localhost’ is invalid and the browser will refuse to set the cookie!

修改登录代码,设置响应cookie,cookie包含jessionid

@Controller
public class LoginController {
private static Logger LOGGER = Logger.getLogger(LoginController.class);

@RequestMapping(“/login”)
public void login(HttpServletRequest request, HttpServletResponse response)
throws IOException {

LOGGER.info(“request /login”);
String username = request.getParameter(“username”);
String password = request.getParameter(“password”);

// 请求转发的方式:
//request.getRequestDispatcher(“success.jsp”).forward(request,response);
//<jsp:forward page=”success.jsp” />
if (“admin”.equalsIgnoreCase(username) && “123456”.equals(password)) {

SysUser user = new SysUser(1L, username, password,
“lvzhongqian@huawei.com”, new Date());
LOGGER.info(“——login successed !——“);
HttpSession session = request.getSession();
session.setAttribute(“user”, user);
LOGGER.info(“set cookie JSESSIONID:” + session.getId());
Cookie responseCookie = new Cookie(“JSESSIONID”, session.getId());
responseCookie.setPath(“/”);
response.addCookie(responseCookie);

/*Cookie[] requestCookies = request.getCookies();
if (null != requestCookies) {
for (Cookie cookie : requestCookies) {
if(“JSESSIONID”.equalsIgnoreCase(cookie.getName())){
LOGGER.info(“set cookie JSESSIONID:” + cookie.getValue());
Cookie responseCookie = new Cookie(cookie.getName(), cookie.getValue());
responseCookie.setPath(“/”);
response.addCookie(responseCookie);
}
}
}*/
response.sendRedirect(“/dicts”);

} else {
response.sendRedirect(“/gotoLogin”);
}

}

@RequestMapping(value = { “”, “/gotoLogin” })
public ModelAndView gotoLogin() {
ModelAndView mv = new ModelAndView(“login”);
return mv;
}

}

4

1)、直接访问应用服务器https://127.0.0.1:8443/gotoLogin:

5

6

7

2)、http://www.lvzhongqian.com/gotoLoin访问应用

8

9

 

请求/dicts就上传的jessionid的值是登录成功时设置的响应jessionid,这样保持session不变,就可以取到session中设置的user值:

10

11

Posted in IT

Author: ilvzhongqian

寄意寒星荃不察,我以我血荐轩辕