Java Web实现“十天内免登录”功能
Java Web实现“十天内免登录”功能
一、 功能原理
“十天内免登录”的本质是在客户端(浏览器)持久化一个加密的、唯一的身份凭证,从而让服务器在用户关闭浏览器再次打开时,依然能够识别出他的身份。
其核心流程如下图所示:
flowchart TDA[用户登录] --> B{选择'十天内免登录'?}B -- 是 --> C[服务器生成Token<br>(用户名+随机数+过期时间)]B -- 否 --> D[结束]C --> E[Token与用户关联并存储至数据库]C --> F[Token加密后写入用户浏览器Cookie]E --> G[完成登录]F --> GH[用户再次访问] --> I[服务器读取Cookie中的Token]I --> J{Token验证是否有效?<br>(存在、未过期、匹配)}J -- 无效或不存在 --> K[视为未登录]J -- 有效 --> L[自动登录<br>并根据Token查询对应用户]L --> M[为用户创建登录会话Session]M --> N[完成自动登录]
二、 实现步骤(基于Token方案)
这是一种安全且常用的方案。
-
数据库准备:
- 在用户表中添加两个字段(或使用单独的表):
remember_token
(VARCHAR):用于存放唯一的令牌字符串。token_validity
(DATETIME/TIMESTAMP):用于存放令牌的过期时间。
- 在用户表中添加两个字段(或使用单独的表):
-
登录成功后的处理:
- 用户登录时,如果勾选了“十天内免登录”,服务器除了正常创建Session之外,还需要:
- 生成一个唯一且加密安全的随机令牌 (Token)。
- 计算过期时间(如:当前时间 + 10天)。
- 将令牌和过期时间与当前用户关联,并存入数据库。
- 将令牌和用户名(或用户ID)通过Cookie发送给客户端浏览器。
- 用户登录时,如果勾选了“十天内免登录”,服务器除了正常创建Session之外,还需要:
-
自动登录的过滤与验证:
- 编写一个Filter或Interceptor,在用户访问网站时进行拦截检查。
- 检查顺序:
- 检查请求中是否已有有效的Session?如果有,直接放行。
- 如果没有Session,则检查客户端是否携带了“记住我”的Cookie。
- 如果找到了Cookie,则从中解析出令牌和用户名。
- 根据用户名/用户ID到数据库中查找有效的令牌和过期时间。
- 验证:令牌是否存在、是否匹配、是否未过期。
- 如果验证通过:则自动为用户创建一个新的Session,视为已登录,然后放行。
- 如果验证失败:则删除客户端无效的Cookie,并让其保持未登录状态。
-
退出登录的处理:
- 用户点击退出时,除了要无效化(invalidate)当前的Session,还需要:
- 删除数据库中对该应用户的令牌记录。
- 删除客户端浏览器中存储“记住我”的Cookie(通过设置一个同名的、值为null的、过期时间为0的Cookie来实现)。
- 用户点击退出时,除了要无效化(invalidate)当前的Session,还需要:
三、 核心代码示例
1. 生成并存储Token(登录Servlet中)
// ... 用户密码验证成功后 ...
if ("on".equals(request.getParameter("rememberMe"))) { // 判断是否勾选// 1. 生成随机TokenString token = UUID.randomUUID().toString() + ThreadLocalRandom.current().nextLong();// 更安全的做法是使用 SecureRandom// 2. 计算过期时间 (10天后)long validity = System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 10); // 毫秒Date expiryDate = new Date(validity);// 3. 将Token和过期时间存入数据库(关联对应用户)userService.updateRememberToken(currentUser.getId(), token, expiryDate);// 4. 创建Cookie并发送给客户端Cookie cookie = new Cookie("rememberMe", token);cookie.setMaxAge(60 * 60 * 24 * 10); // 秒为单位,10天cookie.setPath("/"); // 设置为全站有效cookie.setHttpOnly(true); // 防止XSS攻击获取Cookie,重要!// cookie.setSecure(true); // 如果使用HTTPS,请启用此选项response.addCookie(cookie);
}// 正常创建Session
HttpSession session = request.getSession();
session.setAttribute("user", currentUser);
response.sendRedirect("home.jsp");
2. 自动登录过滤器 (AutoLoginFilter)
@WebFilter("/*") // 拦截所有请求
public class AutoLoginFilter implements Filter {@Overridepublic void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) req;HttpServletResponse response = (HttpServletResponse) resp;HttpSession session = request.getSession(false); // 获取现有session,不创建新session// 1. 如果用户session已存在,直接放行if (session != null && session.getAttribute("user") != null) {chain.doFilter(request, response);return;}// 2. 检查Remember-Me CookieCookie[] cookies = request.getCookies();String rememberMeToken = null;if (cookies != null) {for (Cookie cookie : cookies) {if ("rememberMe".equals(cookie.getName())) {rememberMeToken = cookie.getValue();break;}}}// 3. 如果找到了Cookieif (rememberMeToken != null) {// 调用Service,通过Token查找用户信息(包含过期时间)User user = userService.findByRememberToken(rememberMeToken);// 4. 验证Token和用户是否存在且未过期if (user != null && user.getTokenValidity().after(new Date())) {// 验证成功,自动为用户创建Sessionsession = request.getSession();session.setAttribute("user", user);// 可以选择更新Token有效期(滑动过期时间)} else {// Token无效或已过期,删除客户端的Cookieif (user == null) {// 数据库无此Token,清理无效CookieCookie cookie = new Cookie("rememberMe", null);cookie.setMaxAge(0);cookie.setPath("/");response.addCookie(cookie);}}}// 5. 继续执行后续的过滤器或请求chain.doFilter(request, response);}
}
四、 安全考量与最佳实践
- Token必须是不可预测的:使用
SecureRandom
或UUID
生成高熵(高随机性)的令牌,防止攻击者暴力猜测。 - HttpOnly Cookie:设置Cookie的
HttpOnly
属性为true
,防止JavaScript窃取Cookie(防御XSS攻击)。 - Secure Cookie:如果你的网站使用HTTPS,务必设置Cookie的
Secure
属性为true
,保证Cookie只在加密通道中传输。 - 令牌仅使用一次:更安全的做法是每次自动登录后都生成一个新的令牌替换掉旧的,并更新数据库和Cookie。
- 关联用户ID而非用户名:在Cookie中,可以存储
userId:token
的组合,而不是username:token
,因为ID通常是不可变的,且更难被枚举。 - 重要操作需重新认证:即使用户通过“记住我”功能保持了登录状态,在进行修改密码、支付等敏感操作时,应要求用户重新输入密码进行验证。
- 提供注销选项:一定要提供明显的“退出登录”功能,并正确清理Session和Cookie。
通过以上步骤,你就可以在Java Web项目中实现一个相对安全可靠的“十天内免登录”功能了。