Spring MVC环境下JSP登录页如何实现记住我功能?
现有代码核心问题梳理
- Cookie提取逻辑缺失:
checkCookie方法从请求中拿到了Cookie存储的账号、密码字符串,但从未给新建的空User对象赋值,直接返回空的User实例,根本无法传递有效用户信息 - 逻辑分支错位:控制器内new了一个全新的空User对象做非空校验,永远无法进入写Cookie的分支,完全没有执行实际的账号密码有效性校验
- 接口路径不匹配:登录表单的提交路径是
/verify,但所有Cookie写入逻辑都挂载在adminlogin接口下,表单提交的请求根本无法触发对应逻辑 - Cookie配置缺失:没有给Cookie设置生效路径,默认绑定当前接口路径,会导致其他页面请求时无法读取到已存储的Cookie
- 安全风险:计划明文存储用户账号、密码到Cookie,存在被前端脚本窃取、跨站攻击泄露的风险
修正后的可落地实现
1. 工具类方法完善(Cookie读取与自动登录校验)
替换原有逻辑残缺的checkCookie方法,补全账号赋值、有效性校验的流程:
public User checkCookie(HttpServletRequest request) { // 空Cookie数组判断,避免空指针 Cookie[] cookies = request.getCookies(); if (cookies == null) { return null; } String savedUsername = null; String savedCredential = null; // 遍历Cookie提取持久化的登录凭证 for (Cookie cookie : cookies) { if ("remember_login_username".equals(cookie.getName())) { savedUsername = cookie.getValue(); } if ("remember_login_credential".equals(cookie.getName())) { savedCredential = cookie.getValue(); } } // 凭证齐全时,调用业务层做账号有效性校验,匹配合法用户才放行自动登录 if (savedUsername != null && savedCredential != null) { // 替换为你项目中实际的用户校验逻辑 return userService.verifyLogin(savedUsername, savedCredential); } return null; }
2. 控制器逻辑拆分修正
将原有写在同一个接口里的混杂逻辑,拆分为「展示登录页」和「处理登录提交」两个独立接口,分别对应GET和POST请求:
// 展示登录页的GET接口,进入时优先检查自动登录凭证 @RequestMapping(value = UrlPath.adminlogin, method = RequestMethod.GET) public ModelAndView showLoginPage(HttpServletRequest request, HttpSession session) { // 优先检查当前会话是否已有有效登录态 User currentUser = (User) session.getAttribute("loginUser"); if (currentUser == null) { // 会话失效时检查Cookie中的持久化凭证 currentUser = checkCookie(request); if (currentUser != null) { // 凭证有效,写入会话完成自动登录,直接跳转后台首页 session.setAttribute("loginUser", currentUser); return new ModelAndView(UrlPath.adminHome); } } // 无有效登录态,返回登录页 ModelAndView mv = new ModelAndView(UrlPath.adminlogin); mv.addObject("user", new User()); return mv; } // 处理登录表单提交的POST接口,匹配表单的action="/verify"路径 @RequestMapping(value = "/verify", method = RequestMethod.POST) public ModelAndView handleLoginSubmit( @RequestParam("username") String username, @RequestParam("password") String password, @RequestParam(value = "remember", required = false) String rememberFlag, HttpSession session, HttpServletResponse response ) { // 第一步:校验用户提交的账号密码是否合法 User loginUser = userService.verifyLogin(username, password); if (loginUser == null) { // 校验失败,返回登录页并提示错误 ModelAndView mv = new ModelAndView(UrlPath.adminlogin); mv.addObject("errorMsg", "账号或密码错误"); return mv; } // 校验通过,写入会话保存登录态 session.setAttribute("loginUser", loginUser); // 如果用户勾选了“记住我”,写入持久化Cookie if (rememberFlag != null) { // 存储用户名的Cookie Cookie userCookie = new Cookie("remember_login_username", loginUser.getUsername()); userCookie.setPath("/"); // 设置根路径生效,避免跨路径读不到Cookie userCookie.setMaxAge(7 * 24 * 3600); // 设置7天有效期 userCookie.setHttpOnly(true); // 禁止前端JS读取,降低XSS窃取风险 // 存储加密后的登录凭证,不要存明文密码 Cookie credentialCookie = new Cookie("remember_login_credential", loginUser.getEncryptedCredential()); credentialCookie.setPath("/"); credentialCookie.setMaxAge(7 * 24 * 3600); credentialCookie.setHttpOnly(true); response.addCookie(userCookie); response.addCookie(credentialCookie); } // 登录成功跳转后台首页 return new ModelAndView(UrlPath.adminHome); }
落地注意事项
- Cookie命名避免过于通用:不要直接用
username、password作为Cookie名称,防止和其他站点的同名Cookie冲突,导致读取串值 - 不要明文存储密码:Cookie中存储的凭证要做不可逆加密,或者使用随机生成的长期Token关联用户账号,避免Cookie泄露后用户密码直接暴露
- 退出登录需主动清除Cookie:用户主动触发退出操作时,要将对应两个Cookie的MaxAge设为0,主动删除持久化凭证,防止后续自动登录
- 开发阶段可通过浏览器开发者工具的应用面板,检查Cookie的路径、有效期、值是否正确写入,排查读取问题
内容的提问来源于stack exchange,提问作者Rakhi Sharma
相关产品推荐
相关产品推荐

