本文通過分析博客園登錄流程,揭示 Cookie 自動登錄本質,並提供基於 Struts2 + Servlet Filter 的完整 Demo 實現。
Cookie 是瀏覽器自動攜帶的鍵值對,屬於特定域名/路徑。伺服器通過 Set-Cookie 响應頭下發,瀏覽器後續請求自動附帶 Cookie 請求頭。關鍵屬性:Domain、Path、Expires/Max-Age、HttpOnly、Secure、SameSite。
SERVERID 等),關閉瀏覽器即失效。.CNBlogsCookie,Max-Age=-1(會話級),關閉瀏覽器失效。.CNBlogsCookie 設置 Max-Age=2592000(30 天),持久化到硬盤,下次訪問自動攜帶,伺服器驗證通過即自動登錄。loginUI.jsp(jQuery 讀取 Cookie 預填用戶名)、successUI.jspLoginAction 處理表單登錄、生成 Token、下發 CookieLoginFilter 攔截受保護資源,優先驗證 Session,失效則嘗試 Cookie 自動登錄CookieUtil 解析 Cookie、驗證 Token、重建 SessionUserDao 操作 user 表(含 hobby 字段存儲 UUID Token)// 登錄成功後
String uuid = UUID.randomUUID().toString().replace("-", "");
user.setHobby(uuid); // 存入資料庫
userDao.updateUser(user);
String token = URLEncoder.encode(user.getUsername() + "," + uuid, "UTF-8");
Cookie cookie = new Cookie("loginInfo", token);
cookie.setMaxAge(60 * 60); // 1 小時演示
cookie.setPath("/");
response.addCookie(cookie);
public boolean loginByCookies(HttpServletRequest req, HttpServletResponse resp) {
Cookie[] cookies = req.getCookies();
if (cookies != null) {
for (Cookie c : cookies) {
if ("loginInfo".equals(c.getName())) {
String val = URLDecoder.decode(c.getValue(), "UTF-8");
String[] parts = val.split(",");
User user = userDao.findByUsernameAndHobby(parts[0], parts[1]);
if (user != null) {
req.getSession().setAttribute("loginUser", user);
return true;
}
}
}
}
return false;
}
<filter> <filter-name>loginFilter</filter-name> <filter-class>top.bwcx.cookie.filter.LoginFilter</filter-class> </filter> <filter-mapping> <filter-name>loginFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- Struts2 filter 放在後面 -->
setMaxAge > 0 持久化,< 0 會話級,= 0 刪除。HttpOnly、Secure、SameSite=Strict、Token 定期輪換、防 CSRF。
