0、业务需求
会话:web应用中的会话是指一个客户端浏览器和服务器之间连续发生的一系列请求和响应的过程。
会话状态:web应用中的会话状态是指web服务器与浏览器在会话过程中产生的状态信息,借助会话状态,服务器能够把属于同一会话中的一系列的请求和响应过程关联起来。
Web应用程序是使用HTTP协议传输数据的。HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。即用户A购买了一件商品放入购物车内,当再次购买商品时服务器已经无法判断该购买行为是属于用户A的会话还是用户B的会话了。要跟踪该会话,必须引入一种状态保持机制。
Web应用开发中,存储和管理用户状态是至关重要的。为了实现这一目标,开发者通常依赖于两种主要机制:Cookie和Session。尽管它们都是为了维护用户状态而设计的,但它们在实现方式、安全性、存储位置和容量等方面存在一些显著的区别。
Cookie存储在浏览器中,可以设置过期时间,而Session存储在服务器端,关闭浏览器后自动失效。Session相对于Cookie更安全,但仍然存在安全风险。Session可以存储任意类型的数据,而Cookie有大小限制。选择Session或Cookie应考虑应用场景和安全性要求。
咱们接着聊一下Session。
一、什么是Session
Session 是 Web 开发中常用的一种服务器端状态管理机制,它用于在服务器端存储用户的会话信息,以实现跨页面和跨请求的数据共享。
二、Session的实现原理
存储在服务器端。当用户访问网站时,服务器会为该用户创建一个唯一的Session ID,并将其发送给用户的浏览器。浏览器将这个Session ID存储在Cookie中(注意这里的Cookie仅用于存储Session ID,而非用户信息)。之后,每当用户与服务器进行交互时,浏览器都会将这个Session ID发送给服务器。服务器根据这个Session ID查找对应的Session数据,从而识别用户并提供服务。
三、Session的优点
在安全性方面,Session相对于Cookie更为安全。由于Cookie存储在客户端的浏览器中,因此容易受到跨站脚本攻击(XSS)等安全威胁。攻击者可以通过窃取或篡改Cookie中的信息来冒充用户或窃取用户的敏感信息。而Session数据存储在服务器端,相对较难被攻击者直接访问或篡改。当然,这并不意味着Session就完全没有安全风险。如果服务器的安全措施不到位,或者存在其他漏洞,攻击者仍然有可能通过其他途径获取到Session数据。
四、Session的限制
然而,Session也有一些潜在的缺点。首先,由于Session数据存储在服务器端,因此需要额外的资源来管理和维护这些会话。这可能会增加服务器的内存消耗和复杂性。其次,Session通常具有较短的超时时间,这是为了防止服务器资源被长时间占用。这意味着如果用户在一个会话期间长时间没有活动,他们的会话可能会自动失效,从而导致他们需要重新进行身份验证或重新开始他们的会话。最后,Session通常是域特定的,这意味着它们通常只能在创建它们的同一Web域内有效。这使得跨域Session共享变得更加复杂和具有挑战性。
五、Session什么时候被创建
一个常见的错误是以为session在有客户端访问时就被创建,然而事实是直到某server端程序(如Servlet)调用HttpServletRequest.getSession(true)这样的语句时才会被创建。
六、Session什么时候被删除
session在下列情况下被删除:
A.程序调用HttpSession.invalidate()
B.距离上一次收到客户端发送的session id时间间隔超过了session的最大有效时间
C.服务器进程被停止
再次注意关闭浏览器只会使存储在客户端浏览器内存中的session cookie失效,不会使服务器端的session对象失效。
七、浏览器禁用Cookie怎么存储Sessionid?
前面红色字体讲到服务器创建sessionid后发送给浏览器,浏览器保存在cookie中,如果浏览器cookie被禁用该怎么办呢?必须有其它的机制以便在cookie被禁止时仍然能够把session id传递回服务器,经常采用的一种技术叫做URL重写,就是把session id附加在URL路径的后面,附加的方式也有两种,一种是作为URL路径的附加信息,另一种是作为查询字符串附加在URL后面。网络在整个交互过程中始终 保持状态,就必须在每个客户端可能请求的路径后面都包含这个session id。
八、简单示例
目标:
首先,创一个登录页面login.html,通过post方法提交到loginservlet。
然后,在loginservelt里面进行验证,验证通过则显示登录成功,并在后面添加一个logout链接,该链接指向另外一个logoutservlet,因为通过链接跳转过去的,所以请求出发logoutservlet中的doget方法。
最后我们写一个退出的logoutservlet,该servlet销毁session,使得其不再保存session,验证退出后能否直接登录。
1、新建login.html
添加如下代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<body>
<form action="LoginServlet" method="post">
<table>
<tr>
<td>用户名:</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password"></td>
</tr>
<tr><td>自动登录:<input type="checkbox" name="checkbox1"></td><td><input type="submit" value="登录"></td></tr>
</table>
</form>
</body>
</html>
2、新建LoginServlet
熟悉我内容的朋友,前面应该看到了创建过一个loginservlet的java程序,现在我就不新建了,直接修改那个文件,修改doPost方法。
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//设置参数解析编码格式
String username = request.getParameter("username");
String password = request.getParameter("password");
// 获取页面自动登录框的值
String checkbox1 = request.getParameter("checkbox1");
String jsessionid = null;
HttpSession session = null;
Cookie cookie;
// 先判断是否有cookies
Cookie[] cookies = request.getCookies();
// 如果没有cookies,则从session中获取sessionid存入cookies中,
// 当我们getSession(),sessionid自动存入cookies中,但是我们要修改它cookies的生命周期这里设置为15秒
if (cookies == null) {
session = request.getSession();
// 获取sessionid
jsessionid = session.getId();
// Cookie名与路径一致时,可修改Cookie
cookie = new Cookie("JSESSIONID", jsessionid);
cookie.setPath("/");
// 生命周期这里设置为15秒
cookie.setMaxAge(15);
response.addCookie(cookie);
// 有cookie
} else {
// jsessionid=session.getId();需要用到session
session = request.getSession();
// 如果有cookie, 遍历cookies 是否有sessionid,有则为之前设置的sessionid的cookie还在生命周期内,无需从session中获取sessionid存入cookies中
// 在生命周期内关闭打开浏览器,还是一样的sessionid(JSESSIONID)
for (Cookie cookie1:cookies){
String name = cookie1.getName();
if (name.equals("JSESSIONID")){
jsessionid=session.getId();
break;
};
}
// 如果找不到sessionid,则从session中获取sessionid存入cookies中,
if (jsessionid==null){
jsessionid = session.getId();
cookie = new Cookie("JSESSIONID", jsessionid);
cookie.setPath("/");
// 生命周期这里设置为15秒
cookie.setMaxAge(15);
response.addCookie(cookie);
}
}
// 判断自动登录框是否被选择
boolean check = checkbox1 == null ? false : true;
// autho用于判断用户是否勾选自动登录,并登录成功的数据,下面设置autho的value为1来表示自动登录。
response.setContentType("text/html;charset=utf-8");
Integer autho = (Integer) session.getAttribute("autho");
if (autho != null && autho == 1) {
// 在session中查到用户勾选自动登录数据auto,若auto==1,无需输入用户名密码,点击登入直接展示相应页面
response.getWriter().write("您已登录,欢迎您! " + "<a href='LogoutServlet'>退出并销毁session</a>");
} else {
if (username.equals("zhangsan") && password.equals("111")) {
// 当自动登录被选择时候,在session保存一个key:autho的value为1 用于存储用户已勾选自动登数据
if (check) {
session.setAttribute("autho", 1);
}
// 没有勾选自动登录,账号密码输入成功,登录成功,点击退出可以回到登录页面
response.getWriter().write("登录成功! " + "<a href='LogoutServlet'>退出并销毁session</a>");
} else if (username.equals("") || password.equals("") || username == null || password == null) {
// 账号密码任意框没有输入值的提示,2秒后重定向到登录页面
response.getWriter().write("请输入用户名登录! ");
response.setHeader("Refresh", "2;url=login.html");
} else {
// 账号密码输入错误,2秒后重定向到登录页面
response.getWriter().write("登录失败! " + "<a href='login.html'>自动返回登录页面</a>");
response.setHeader("Refresh", "2;url=login.html");
}
}
}
3、新建LogoutServlet
修改一下doGet方法如下:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
HttpSession session = request.getSession(false);
if (session != null) {
session.removeAttribute("autho");
session.invalidate();
}
response.sendRedirect("login.html");
return;
}
4、测试效果
第一次登录,输入错误的用户名密码,页面自动跳转会登录页面:
点击登录后显示并返回登录页
然后我们输入zhangsan和111并点击记住密码复选框
点击登录跳转
此时,我们直接url返回登录页面
直接点击登录
这次我们点击退出并销毁session,页面会返回登录页面
再次直接点击登录按钮
提示请输入用户名,然后跳转到登录页面
参考资料:
https://baijiahao.baidu.com/s?id=1792235103352395317&wfr=spider&for=pc
https://baijiahao.baidu.com/s?id=1786997538208967885&wfr=spider&for=pc
https://blog.csdn.net/java_faep/article/details/78082802
https://blog.csdn.net/J080624/article/details/78562787
https://blog.csdn.net/afeifu/article/details/137249053