小明:最近我在做一个校园教材征订管理系统,感觉登录功能挺关键的,你怎么看?
小李:确实,登录是整个系统的基础。没有安全的登录机制,系统就容易被恶意攻击,数据也得不到保障。
小明:那你是怎么设计登录模块的呢?有没有什么特别需要注意的地方?
小李:首先,我用的是JavaWeb技术栈,采用Servlet + JSP + JDBC来实现登录功能。登录页面使用JSP展示,提交到一个Servlet处理。
小明:哦,那具体是怎么做的呢?能给我看看代码吗?
小李:当然可以。我们先从登录页面开始,这是JSP文件:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
教材征订系统登录
小明:看起来很基础,那Servlet是怎么处理的?
小李:接下来是Servlet部分,这里负责接收表单数据,并进行验证。下面是LoginServlet.java的代码:
package com.example.login;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.sql.*;
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/textbook_system", "root", "123456");
String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, username);
stmt.setString(2, password);
ResultSet rs = stmt.executeQuery();
if (rs.next()) {
// 登录成功,跳转到主页
response.sendRedirect("home.jsp");
} else {
// 登录失败,返回登录页
request.setAttribute("error", "用户名或密码错误");
request.getRequestDispatcher("login.jsp").forward(request, response);
}
rs.close();
stmt.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
request.setAttribute("error", "系统错误,请稍后再试");
request.getRequestDispatcher("login.jsp").forward(request, response);
}
}
}
小明:这段代码看起来没问题,但安全性方面有什么考虑吗?比如SQL注入或者密码明文存储?
小李:你说得对,这里确实存在安全隐患。我后来加了PreparedStatement来防止SQL注入,但密码还是明文存储在数据库中,这样不安全。
小明:那怎么办呢?是不是应该加密存储密码?
小李:没错,我之后改成了使用MD5加密密码。不过MD5现在也不推荐用了,建议用更安全的算法,比如BCrypt。
小明:那能不能再举个例子,比如如何用BCrypt加密和验证?
小李:好的,下面是一个使用BCrypt的示例。首先,你需要引入BCrypt库,比如通过Maven添加依赖:
小明:明白了。那在注册的时候怎么加密密码呢?
小李:注册时,使用BCrypt.hashpw方法对密码进行哈希处理,然后存入数据库。例如:
String hashedPassword = BCrypt.hashpw(rawPassword, BCrypt.gensalt());
// 将hashedPassword存入数据库
小明:那登录时怎么验证呢?
小李:登录时,从数据库取出哈希后的密码,然后用BCrypt.checkpw方法进行比对:
String storedHash = ...; // 从数据库获取

boolean isValid = BCrypt.checkpw(inputPassword, storedHash);
小明:这样就更安全了。那登录成功后,怎么管理用户会话呢?
小李:通常我们会使用HttpSession来管理用户状态。例如,在登录成功后,将用户信息存入session中:
HttpSession session = request.getSession();
session.setAttribute("user", user); // user是用户对象
小明:那在其他页面中,怎么判断用户是否已经登录?
小李:可以在每个需要登录访问的页面开头检查session是否存在用户信息。如果不存在,就跳转回登录页。
小明:听起来逻辑清晰。那有没有什么常见的问题需要注意?
小李:比如,不要在日志中记录密码,避免跨站脚本攻击(XSS),以及设置合适的Cookie属性,如HttpOnly、Secure等。
小明:嗯,这些都很重要。那你觉得这个系统还可以扩展哪些功能?
小李:可以加入角色权限管理,比如管理员、教师、学生不同权限;还可以加入验证码防止暴力破解;甚至可以集成微信或QQ登录。
小明:听起来很有意思。看来登录模块虽然简单,但背后有很多技术细节需要考虑。
小李:没错,一个好的登录系统不仅关系到用户体验,还直接影响到系统的安全性。
小明:谢谢你详细的讲解,我现在对这个系统有了更深的理解。
小李:不客气,如果你有更多问题,随时可以问我。
