功能流程
LoginServlet — 顯示登錄表單(GET)。
LoginClServlet — 接收提交,PreparedStatement 防注入查詢,驗證成功創建 HttpSession,重定向歡迎頁。
WelcomeServlet — 攔截未登錄請求,校驗 Session,顯示歡迎信息。
代碼實現
1. 登錄頁面 Servlet (LoginServlet)
package com.bai;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.*;
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
out.println("");
out.println("用戶登錄
");
out.println("");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp); // 表單提交也走 doGet 邏輯(實際專案分離)
}
}
2. 登錄處理 Servlet (LoginClServlet)
package com.bai;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.*;
import java.sql.*;
public class LoginClServlet extends HttpServlet {
private static final String SQL = "SELECT passwd FROM users WHERE username = ? LIMIT 1";
private static final String JDBC_URL = "jdbc:mysql://localhost:3306/sqdb";
private static final String DB_USER = "root";
private static final String DB_PASS = "root";
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("passwd");
try (Connection conn = DriverManager.getConnection(JDBC_URL, DB_USER, DB_PASS);
PreparedStatement ps = conn.prepareStatement(SQL)) {
ps.setString(1, username);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
String dbPass = rs.getString("passwd");
if (password.equals(dbPass)) { // 實際應用應用 BCrypt 比對哈希
HttpSession session = req.getSession(true);
session.setMaxInactiveInterval(30 * 60); // 30 分鐘
session.setAttribute("username", username);
resp.sendRedirect("welcome");
return;
}
}
// 驗證失敗
resp.sendRedirect("login");
}
} catch (SQLException e) {
throw new ServletException("數據庫錯誤", e);
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
}
3. 歡迎頁 Servlet (WelcomeServlet)
package com.bai;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.*;
public class WelcomeServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession(false); // 不自動創建
String username = (session != null) ? (String) session.getAttribute("username") : null;
if (username == null) {
resp.sendRedirect("login");
return;
}
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
out.println("");
out.println("歡迎, " + username + "!
");
out.println("退出登錄");
out.println("");
}
}
4. 登出 Servlet (可選)
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
HttpSession session = req.getSession(false);
if (session != null) session.invalidate();
resp.sendRedirect("login");
}
}
web.xml 註冊 (或用 @WebServlet 註解)
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>com.bai.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>LoginClServlet</servlet-name>
<servlet-class>com.bai.LoginClServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginClServlet</servlet-name>
<url-pattern>/logincl</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>WelcomeServlet</servlet-name>
<servlet-class>com.bai.WelcomeServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>WelcomeServlet</servlet-name>
<url-pattern>/welcome</url-pattern>
</servlet-mapping>
安全加固清單
- ✅ PreparedStatement 防 SQL 注入。
- ✅ 密碼不應明文存儲,使用 BCrypt/Argon2 哈希(
BCrypt.checkpw(input, hash))。
- ✅ Session 設置
HttpOnly、Secure(HTTPS 環境)、SameSite=Strict。
- ✅ 登錄失敗通用提示(「用戶名或密碼錯誤」),不洩露用戶是否存在。
- ✅ 添加驗證碼/限流防暴力破解。
- ✅ 關鍵操作記錄審計日誌(IP、時間、結果)。