正常情况下,我们要请求一个网站内的不同资源文件时,需要我们先登录,然后才能执行部分权限,比如我们模拟要查询一个网站内的所有商品信息,步骤是先登录,登录成功后进入主页,然后查询相关信息,如下图

Servlet过滤器使用实例(防止用户恶意登录)_Servlet
但是,我们也会遇到恶意登录的情况,就是跳过登录这一步,直接从地址栏中访问网站内的资源,如下图

Servlet过滤器使用实例(防止用户恶意登录)_Servlet_02
Servlet过滤器使用实例(防止用户恶意登录)_Servlet_03
虽然访问成功是概率性的,但是也是有这个可能的,既然有可能发生,那么对我们网站的安全就有很大的威胁,所以,我们可以使用过滤器来避免这种情况的发生

过滤器可以在用户通过浏览器向服务器发送请求时,将浏览器发送的请求进行拦截,过滤器也就相当于是浏览器和服务器之间传送信息的使者,信息传送的成功与否完全取决于它,我们可以在过滤器中定义规则来控制浏览器的请求是否可以发送至服务器,如果浏览器发送的请求满足我们定义的规则,我们可以将浏览器请求返回给服务器,这样就可以在服务器完成用户的请求,如果浏览器的请求不满足我们定义的规则,我们可以选择不将浏览器的请求返回给服务器,直接在过滤器中进行处理

实现思路:针对我们上述遇到的问题,我们首先要区分正常登录用户和恶意登录用户,当正常登录用户成功登录后我们可以为用户创建session对象,然后我们可以在过滤器中定义规则来判断该用户的session是否为空,如果不为空,说明该用户登录成功,我们可以将用户的请求返回给服务器,使用户成功访问到网站内的资源,如果为空,说明该用户没有登录或者登录失败,这时我们可以在过滤器中拦截该用户访问网站内其他资源的请求,然后将该请求重定向到其他网页或输出语句来提示用户

改进效果

Servlet过滤器使用实例(防止用户恶意登录)_Servlet_04
Servlet过滤器使用实例(防止用户恶意登录)_Servlet_05

代码部分

项目结构

其中LoginFilter.java是过滤器接口的实现类,我们在此类中定义请求拦截规则

Servlet过滤器使用实例(防止用户恶意登录)_Servlet_06
LoginDao.java部分

package dao;import java.sql.*;import util.SqlServerConnection;public class LoginDao {private Connection conn = null;private PreparedStatement pst = null;private ResultSet rst = null;public boolean login(String name,String password) {boolean result = false;try {
			conn = SqlServerConnection.sql_connection();
			pst = conn.prepareStatement("select * from tb_user where username=? and password=?");
			pst.setString(1, name);
			pst.setString(2, password);
			rst = pst.executeQuery();if (rst.next()) {
				result = true;}} catch (SQLException e) {// TODO Auto-generated catch block
			e.printStackTrace();}finally {
			SqlServerConnection.unconnect(rst, pst, conn);}return result;}}

LoginFilter.java部分

package filter;import java.io.IOException;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;public class LoginFilter implements Filter {@Overridepublic void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain chain)throws IOException, ServletException {// TODO Auto-generated method stub
		HttpServletRequest request = (HttpServletRequest) arg0;
		HttpServletResponse response = (HttpServletResponse) arg1;//		在网站中获取session对象,如果没有则返回null
		HttpSession session = request.getSession(false);//		获取请求地址uri
		String uri = request.getRequestURI();//		当访问login.html文件时获取到的URI为 /WebTest5/,允许带有‘Login’关键字的请求通过if (uri.equals("/WebTest5/") || uri.indexOf("Login") != -1) {
			chain.doFilter(arg0, arg1);return;}//		允许访问登录失败页面if (uri.indexOf("error") != -1) {
			chain.doFilter(arg0, arg1);return;}//		如果session不为空,表明该用户为正常登录用户且成功登录,允许用户请求通过if (session != null) {
			chain.doFilter(arg0, arg1);return;}//		如果session为空,表明该用户不是正常登录用户或登录失败,将请求重定向到登录失败页面if (session == null) {
			response.sendRedirect("error.html");return;}}}

AllInfo.java部分

package servlet;import java.io.IOException;import java.io.PrintWriter;import java.sql.*;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 util.SqlServerConnection;@WebServlet("/AllInfo")public class AllInfo extends HttpServlet {private static final long serialVersionUID = 1L;   public AllInfo() {super();// TODO Auto-generated constructor stub}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter();
		PreparedStatement pst = null;
		Connection conn = null;
		ResultSet rst = null;
		String output = "<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>";try {
			out.print("<center>");
			out.print("<table border='1'>");
			conn = SqlServerConnection.sql_connection();
			pst = conn.prepareStatement("select * from Product");
			rst = pst.executeQuery();while (rst.next()) {
				String a = rst.getString("p_type");
				String b = rst.getString("p_id");
				String c = rst.getString("p_name");
				String d = rst.getString("p_price");
				String e = rst.getString("p_quantity");
				String f = rst.getString("p_image");
				String g = rst.getString("p_description");
				String h = rst.getString("p_time");
				out.print(String.format(output, a,b,c,d,e,f,g,h));}
			out.print("</table>");
			out.print("</center>");} catch (SQLException e) {// TODO Auto-generated catch block
			e.printStackTrace();}}}

LoginServlet.java部分

package servlet;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 javax.servlet.http.HttpSession;import dao.LoginDao;@WebServlet("/LoginServlet")public class LoginServlet extends HttpServlet {private static final long serialVersionUID = 1L;   public LoginServlet() {super();// TODO Auto-generated constructor stub}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");
		String name = request.getParameter("name");
		String password = request.getParameter("password");
		LoginDao loginDao = new LoginDao();boolean result = loginDao.login(name, password);if (result == true) {//			当用户成功登录后,为用户创建session对象
			HttpSession session = request.getSession();
			response.sendRedirect("success.html");}else {//			当用户登录失败,直接跳转到登录失败页面
			response.sendRedirect("error.html");}}}

SqlServerConnection.java部分

package util;import java.sql.*;public class SqlServerConnection {static Connection conn;static String drive = "com.microsoft.sqlserver.jdbc.SQLServerDriver";static String url = "jdbc:sqlserver://localhost:1433;DatabaseName=ShopSystem";static String username = "sa";static String password = "sa";public static Connection sql_connection() {try {//		注册驱动
			Class.forName(drive);} catch (ClassNotFoundException e) {// TODO Auto-generated catch block
			e.printStackTrace();}try {//			创建连接对象
			conn = DriverManager.getConnection(url,username,password);} catch (SQLException e) {// TODO Auto-generated catch block
			e.printStackTrace();
			System.out.println("连接失败");}return conn;}public static void unconnect(ResultSet rst,PreparedStatement pst,Connection conn) {if (rst != null) {try {
				rst.close();} catch (SQLException e) {// TODO Auto-generated catch block
				e.printStackTrace();}}if (pst != null) {try {
				pst.close();} catch (SQLException e) {// TODO Auto-generated catch block
				e.printStackTrace();}}if (conn != null) {try {
				conn.close();} catch (SQLException e) {// TODO Auto-generated catch block
				e.printStackTrace();}}}}

web.xml部分

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0">
  <display-name>WebTest5</display-name>
  <welcome-file-list><welcome-file>login.html</welcome-file><welcome-file>index.html</welcome-file><welcome-file>index.htm</welcome-file><welcome-file>index.jsp</welcome-file><welcome-file>default.html</welcome-file><welcome-file>default.htm</welcome-file><welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <filter>
  <!-- 过滤器名称 可以随便定义 --><filter-name>logfilter</filter-name><!-- 过滤器url 格式为: 包名.类名 --><filter-class>filter.LoginFilter</filter-class>
  </filter>
  <filter-mapping>
  <!-- 过滤器名称 要和上面相同 --><filter-name>logfilter</filter-name><!-- 请求哪个资源文件时调用过滤器  /* 代表网站内所有资源文件 --><url-pattern>/*</url-pattern> 
  </filter-mapping></web-app>

error.html部分

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Insert title here</title></head><body><center><h1 style="color:red">登录失败,请重新登录</h1><form action="LoginServlet" method="post">
		用户名:<input type="text" name="name"><br/>
		密&nbsp;&nbsp;&nbsp;码:<input type="password" name="password"><br/><input type="submit"><br/></form></center></body></html>

login.html部分

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Insert title here</title></head><body><center><form action="LoginServlet" method="post">
		用户名:<input type="text" name="name"><br/>
		密&nbsp;&nbsp;&nbsp;码:<input type="password" name="password"><br/><input type="submit"><br/></form></center></body></html>

success.html部分

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Insert title here</title></head><body><center><h1 style="color:green">登录成功</h1><a href="AllInfo">查看所有商品</a></center></body></html>