B/S会话管理
http基于TCP之上,但是http是无状态的,用户的两次请求不会有任何关联,但是往往实际开发过程中,需要记住用户的登陆状态、上次操作。这时候需要做会话管理。
B/S架构主要的会话管理方式有隐藏域、Cookie、Session管理。
隐藏域
- 该方法基本已经被弃用。
- 由浏览器在每次请求时,主动告诉服务器多次请求间的必要信息
如登陆:
每次浏览器都需要携带帐户、登陆状态请求数据
浏览器接收请求仍需要返回所有下次需要的数据,以便下次请求继续携带
使用Cookie
- Cookie是在浏览器端存储信息的一种方式。
- 由服务器端将需要保存给客户端的数据放入Cookie,并通过HttpServletResponse响应给浏览器
- 默认的Cookie存活时间是关闭浏览器之前,可以通过setMaxAge的设置
- 浏览器再次连接服务器是,浏览器会把有效期内的cookie信息,利用cookie表头自动将Cookie发送给浏览器
Cookie使用场景:下次自动登陆
// 服务端设置Cookie
Cookie cookie = new Cookie("username",username);
cookie.setMaxAge(7*24*60*60);//设置有效时间,单位s,缺省-1,即关闭浏览器cookie失效
cookie.setHttpOnly(true);是否只能在服务端操作cookie,而客户端javascript不能。不是cookie规范,而是浏览器支持
resp.addCookie(cookie);//向response中添加cookie,可以多次调用以添加多个cookie
// 服务端取Cookie校验
Cookie[] cookies = req.getCookies();
if (cookies != null){
for (Cookie cookie : cookies){
if (cookie.getName().equals("username") && cookie.getValue().equals("huqi")){
req.getRequestDispatcher("/home.jsp").forward(req,resp);
break;
}
}
浏览器如何判定这些Cookie是该服务器的呢?
首先主机(域名或者ip)必须一致。这个服务器的地址的父级路径作为路径值和cookie的路径进行匹配,如果服务器地址的路径可以和cookie的路径完全匹配,则将这个cookie发送给服务器的某个页面或者sevlet。所以服务器的某个页面想要拿到某个Cookie,这个页面的路径必须和cookie路径相同或者是他的子路径。
备注:
- 用户可能会关闭Cookie功能
- 攻击者能会伪造Cookie(解决办法:setHttpOnly(true))
其他
- Cookie存在跨域问题,cookie是不能跨域访问的
- Cookie做单点登陆,需要在一级域名下存cookie,子路径可以访问
Session
- Session和Cookie一样由服务器创建,但由服务器进行管理。
HttpSession会话管理
- 浏览器首次请求服务器,服务器收到请求后,由Web容器创建Session,默认加在Cookie中返回给浏览器
- 下次请求时浏览器会将Cookie携带,里面Jsessionid就是Sessionid
- Session销毁并不是Cookie销毁后就销毁(但客户端的sessionid会丢失),而是由服务端管理,Cookie失效后,下次的请求将由web服务器创建新的Session
- 服务端主动清理Session通过调用HttpSession.invalidate()
//web.xml中配置Session过期时间
<session-config>
<session-timeout>30</session-timeout>//单位是分钟
</session-config>
注意
- 浏览器关闭后,即使Cookie没有过期(设置了Cookie过期时间),但是cookie中携带的sessionID会丢失(注意:服务器端的session仍然存在)。
- 再次请求服务器时,会生成新的sessionID,已经不能匹配原来的上次的sessionID了,只有等其过期或者重启浏览器。
- session默认的过期时间是30min。
Token是会话管理工具吗?
- Token是一种认证令牌,主要繁验证用户登陆问题
上面说的Cookie、Session,其实更多的是表示这个请求来源于同一个客户端,没有对认证有更多的要求,无论做不做,服务端都会分配Session
如果要用Cookie做用户登陆认证:登陆成功返回浏览器Token,并将token保存到数据库,每次验证
用Session做登陆认证,登陆成功后,通过session.setAttribute("token",token),每次请求getAttribute和数据库Token对比