在 Web 應用開發中,登錄功能是保障系統安全的第一道防線。本文將結合實際代碼,詳細解析一個基于 Spring Boot 框架的登錄功能實現,包括驗證碼生成、用戶驗證、Token 機制等關鍵環節。
技術棧概覽
本登錄功能實現涉及以下核心技術和組件:
- Spring Boot:后端開發框架
- MyBatis-Plus:數據庫操作增強工具
- Redis:用于存儲驗證碼和 Token
- JWT:生成和驗證用戶令牌
- Hutool:提供 UUID 生成、加密等工具類
- 驗證碼工具:生成圖形驗證碼
核心功能實現
1. 驗證碼生成與驗證
驗證碼是防止惡意登錄的重要手段,實現代碼如下:
@RequestMapping("/captcha")
public Result getCaptcha(){// 生成驗證碼圖片對象Captcha captcha = new SpecCaptcha(130, 38, 4);// 將驗證碼轉為大寫字符串String code = captcha.text().toUpperCase();// 生成UUID作為驗證碼的唯一標識String uuid = IdUtil.simpleUUID();// 存入redis并設置2分鐘過期時間redisTemplate.opsForValue().set(uuid, code, 120, TimeUnit.SECONDS);// 構建返回數據Map<String,Object> map = new HashMap<>();map.put("uuid", uuid); // 驗證碼唯一標識map.put("code", code); // 驗證碼文本map.put("captcha", captcha.toBase64()); // 驗證碼圖片(base64格式)return Result.ok().put("data", map);
}
驗證碼實現流程:
- 生成指定尺寸的圖形驗證碼
- 將驗證碼文本轉為大寫并與 UUID 綁定
- 存儲到 Redis 并設置過期時間
- 將 UUID、驗證碼圖片(base64 格式)返回給前端
2. 登錄核心邏輯
登錄功能是整個流程的核心,負責驗證用戶身份并生成訪問令牌:
@RequestMapping("/login")
public Result login(@RequestBody LoginForm loginForm, HttpSession session){// 1. 驗證驗證碼是否存在String uuid = loginForm.getUuid();String code = (String)redisTemplate.opsForValue().get(uuid);if(code == null){return Result.ok().put("status","驗證碼已過期");}// 2. 驗證驗證碼是否正確String captcha = loginForm.getCaptcha().toUpperCase();if(!code.equals(captcha)){return Result.ok().put("status","驗證碼錯誤");}// 3. 驗證用戶名是否存在String username = loginForm.getUsername();QueryWrapper<UserEntity> queryWrapper = new QueryWrapper<>();queryWrapper.eq("username", username);UserEntity user = userService.getOne(queryWrapper);if(user == null){return Result.ok().put("status","用戶名不存在");}// 4. 驗證密碼是否正確(使用SHA256加密)String password = SecureUtil.sha256(loginForm.getPassword());if(!password.equals(user.getPassword())){return Result.ok().put("status","密碼錯誤");}// 5. 將用戶信息存入sessionsession.setAttribute("user", user);// 6. 生成JWT令牌String token = jwtUtil.createToken(String.valueOf(user.getUserId()));// 7. 準備返回數據Map<String,Object> map = new HashMap<>();map.put("token", token);map.put("expire", jwtUtil.getExpire());return Result.ok().put("data", map);
}
登錄流程解析:
- 前端提交包含用戶名、密碼、驗證碼和 UUID 的登錄表單
- 后端通過 UUID 從 Redis 獲取驗證碼進行驗證
- 驗證通過后查詢數據庫檢查用戶名是否存在
- 對輸入密碼進行 SHA256 加密后與數據庫存儲的密碼比對
- 驗證成功后,將用戶信息存入 session
- 生成 JWT 令牌并返回給前端,用于后續請求的身份驗證
3. Token 驗證機制
為了避免每次請求都需要重新登錄,實現了基于 JWT 的 Token 驗證機制:
@RequestMapping("/checkToken")
public Result checkToken(HttpServletRequest request){String token = request.getHeader("token");boolean result = jwtUtil.checkToken(token);if (result) return Result.ok().put("status","ok");else {return Result.ok().put("status", "error");}
}
Token 驗證流程:
- 前端在請求頭中攜帶 Token
- 后端從請求頭獲取 Token 并驗證其有效性
- 返回驗證結果,前端根據結果判斷是否需要重新登錄
4. 退出登錄功能
@RequestMapping("/logout")
public Result logout(HttpSession session) {session.invalidate(); // 使當前session失效return Result.ok().put("status", "操作成功");
}
退出登錄通過使當前 session 失效,清除用戶的登錄狀態。
安全性考慮
- 密碼加密:使用 SHA256 算法對密碼進行加密存儲,避免明文存儲
- 驗證碼機制:防止機器人自動登錄和暴力破解
- Token 過期機制:JWT 令牌有有效期,降低被盜用風險
- Redis 存儲:驗證碼和 Token 都存儲在 Redis 中并設置過期時間,自動清理
總結
本登錄功能實現了從驗證碼生成、用戶身份驗證到 Token 發放的完整流程,結合了 Redis 和 JWT 技術,既保證了系統安全性,又提升了用戶體驗。在實際應用中,還可以根據需求進一步增強,如添加登錄次數限制、異常登錄檢測等功能。
通過分層驗證(驗證碼 -> 用戶名 -> 密碼)的方式,逐步過濾無效請求,既提高了安全性,也能給用戶提供更明確的錯誤提示。