如果是七天免登录,和session肯定没关系,因为session不能持久化,主要是客户端一旦关闭,seesion就失效了///
所以必须是能持久化的,这就清晰了,要莫在的服务器保存,要摸在客户端设置
cook机制
在登录页面中,提供一个“记住我”选项,允许用户选择是否启用免登录功能。
jsp复制
在登录成功后,根据用户是否勾选“记住我”,设置一个有效期为7天的Cookie。
java复制
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String account = req.getParameter("account");
String password = req.getParameter("password");
String remember = req.getParameter("remember");
// 模拟用户验证
boolean isValidUser = "admin".equals(account) && "123".equals(password);
if (isValidUser) {
// 如果用户勾选了“记住我”
if ("1".equals(remember)) {
Cookie cookie = new Cookie("auth_token", URLEncoder.encode(account + "-" + password, "utf-8"));
cookie.setMaxAge(7 * 24 * 60 * 60); // 设置Cookie有效期为7天
cookie.setPath("/"); // 设置Cookie路径
resp.addCookie(cookie);
}
// 跳转到主页
resp.sendRedirect("index.jsp");
} else {
// 跳转回登录页面
resp.sendRedirect("login.jsp?error=true");
}
}
在用户访问主页时,检查Cookie是否存在并有效。
java复制
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Cookie[] cookies = req.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if ("auth_token".equals(cookie.getName())) {
String[] userInfo = URLDecoder.decode(cookie.getValue(), "utf-8").split("-");
String account = userInfo[0];
String password = userInfo[1];
// 模拟验证用户信息
if ("admin".equals(account) && "123".equals(password)) {
// 自动登录成功,跳转到主页
resp.sendRedirect("index.jsp");
return;
}
}
}
}
// 如果没有找到有效的Cookie,跳转到登录页面
resp.sendRedirect("login.jsp");
}
在用户登录成功后,生成一个有效期为7天的JWT,并将其存储在Cookie中。
java复制
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
public class JwtUtil {
private static final String SECRET_KEY = "your_jwt_secret_key";
public static String generateToken(String subject) {
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
long expMillis = nowMillis + 7L * 24 * 60 * 60 * 1000; // 7天有效期
Date exp = new Date(expMillis);
return Jwts.builder()
.setSubject(subject)
.setIssuedAt(now)
.setExpiration(exp)
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
}
在登录成功后,将JWT存储在Cookie中。
java复制
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String account = req.getParameter("account");
String password = req.getParameter("password");
// 模拟用户验证
boolean isValidUser = "admin".equals(account) && "123".equals(password);
if (isValidUser) {
String token = JwtUtil.generateToken(account);
Cookie cookie = new Cookie("auth_token", token);
cookie.setMaxAge(7 * 24 * 60 * 60); // 设置Cookie有效期为7天
cookie.setPath("/");
resp.addCookie(cookie);
resp.sendRedirect("index.jsp");
} else {
resp.sendRedirect("login.jsp?error=true");
}
}
在每次请求时,验证JWT的有效性。
java复制
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
public class JwtUtil {
private static final String SECRET_KEY = "your_jwt_secret_key";
public static Claims parseToken(String token) {
return Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
}
}
在过滤器中验证JWT。
java复制
@Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse resp, FilterChain filterChain) throws ServletException, IOException {
Cookie[] cookies = req.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if ("auth_token".equals(cookie.getName())) {
try {
Claims claims = JwtUtil.parseToken(cookie.getValue());
// 如果JWT有效,继续处理请求
filterChain.doFilter(req, resp);
return;
} catch (Exception e) {
// JWT无效,跳转到登录页面
resp.sendRedirect("login.jsp");
return;
}
}
}
}
// 如果没有找到有效的JWT,跳转到登录页面
resp.sendRedirect("login.jsp");
}
安全性:为了确保安全性,建议使用HTTPS协议传输数据,避免Cookie或JWT被窃取。
Cookie设置:如果使用Cookie存储JWT,建议设置httpOnly
属性,防止JavaScript访问Cookie,从而降低XSS攻击的风险。
定期更新:定期更新JWT或Cookie的密钥,防止被恶意攻击者破解。
HTTP请求会携带Cookie的原因主要与Cookie的设计初衷和工作原理有关。Cookie是一种存储在客户端(通常是浏览器)的轻量级数据存储机制,用于在用户与服务器之间保持会话状态。以下是详细解释:
保持会话状态:HTTP协议本身是无状态的,这意味着服务器不会自动记住用户之前的请求。每次HTTP请求都是独立的,服务器无法区分是同一个用户还是不同用户发起的请求。为了弥补这一缺陷,Cookie被设计出来,用于在客户端存储少量数据,以便在后续请求中携带这些数据,从而让服务器能够识别用户的身份或状态。
个性化体验:通过Cookie,网站可以记住用户的偏好设置(如语言、主题、登录状态等),从而为用户提供个性化的体验。
服务器设置Cookie:当用户第一次访问网站时,服务器可能会在响应中包含一个Set-Cookie
头,告诉浏览器存储一些数据。例如:
http复制
Set-Cookie: session_id=1234567890; Path=/; HttpOnly
这里,服务器告诉浏览器存储一个名为session_id
的Cookie,值为1234567890
,并且该Cookie适用于网站的所有路径(Path=/
)。
浏览器存储Cookie:浏览器接收到Set-Cookie
头后,会将这些Cookie存储在本地。存储的位置和方式因浏览器而异,但通常会以键值对的形式保存。
浏览器自动携带Cookie:在后续的HTTP请求中,浏览器会自动将与当前请求相关的Cookie附加到请求的Cookie
头中。例如:
http复制
GET / HTTP/1.1
Host: example.com
Cookie: session_id=1234567890
浏览器会根据Cookie的Path
、Domain
等属性,判断哪些Cookie应该附加到当前请求中。
浏览器的自动管理机制:浏览器会自动管理Cookie的存储和发送。当浏览器发起HTTP请求时,它会检查本地存储的Cookie,找出与当前请求匹配的Cookie,并将它们附加到请求的Cookie
头中。这个过程对用户是透明的,用户无需手动添加Cookie。
符合HTTP协议规范:根据HTTP协议的规范,浏览器有责任在每次请求时携带与该请求相关的Cookie。这是为了实现会话管理、身份验证等功能,确保用户在浏览网站时能够保持一致的状态。
匹配Path
和Domain
属性:浏览器只会将与当前请求的URL匹配的Cookie发送给服务器。例如,如果Cookie的Domain
属性是example.com
,那么只有当请求的域名是example.com
时,该Cookie才会被发送。
Cookie未过期:如果Cookie设置了Expires
或Max-Age
属性,浏览器会检查Cookie是否已过期。如果已过期,浏览器不会发送该Cookie。
非HttpOnly
属性的Cookie:如果Cookie设置了HttpOnly
属性,浏览器会阻止JavaScript访问该Cookie,但仍然会在HTTP请求中自动携带。
假设用户访问了一个网站,服务器在响应中设置了以下Cookie:
http复制
Set-Cookie: session_id=1234567890; Path=/; Max-Age=3600
Set-Cookie: theme=dark; Path=/; HttpOnly
存储Cookie:浏览器会将这两个Cookie存储在本地。
后续请求:当用户再次访问该网站时,浏览器会自动将这两个Cookie附加到请求中:
http复制
GET / HTTP/1.1
Host: example.com
Cookie: session_id=1234567890; theme=dark
HTTP请求会携带Cookie,是因为浏览器会自动管理Cookie的存储和发送。这是为了实现会话管理、身份验证和个性化体验等功能。浏览器会根据Cookie的Path
、Domain
、Expires
等属性,判断哪些Cookie应该附加到当前请求中,并在每次请求时自动将它们发送给服务器。
这种机制使得用户在浏览网站时能够保持一致的状态,而无需手动管理Cookie,同时也为开发者提供了方便的方式来实现会话管理和用户跟踪。
参考资料:
Mozilla Developer Network - HTTP Cookies
RFC 6265 - HTTP State Management Mechanism
Google Developers - Cookies Explained
Stack Overflow - How do cookies work?
W3Schools - HTTP Cookies