Find out a Java filter in one article

Keywords: Programming Java JSP Database xml

Filter: Filter

Introduction

We can use the previous technology to make some simple login registration and to cooperate with the database to add or delete data. The program is basically running, but there is a major security problem. That is login rights verification. Generally speaking, the correct login process is as follows:Users inClients make requests - > Background judgment whether to log in - > Yes is unlimited, otherwise jump back to the login page to determine whether to log in and get referer s in Header that we learned earlier and then judge the effect of anti-theft chain has a similar feeling, is to start a judgment filter, and Filter is a better oneThe technology to solve this problem, of course, has more powerful functions than this, so let's talk about it.

(1) Overview of filters

Filter, as its name implies, is a kind of thing that plays a filtering role, but compared to filter in real life, where the filter filters the web resources accessed by clients, or it can be understood as a preprocessing means, after intercepting the resources, the impurities we think (users from)Defined) filters, qualified releases, non-conforming intercepts

Of course, filters can intercept both request s and returned response s, so let's take a look at the graph

(2) First filter procedure

The essence of a filter is a Java class that implements the Filter interface

Let's first create our own class, implement the Filter interface (javax.servlet), and override all of its methods

@WebFilter("/*")
public class FilterDemo1 implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //Release Code
        chain.doFilter(req, resp);
    }

    public void init(FilterConfig config) throws ServletException {
    }

}

Let's not explore any of these first, let's look at how to configure the filter

(3) filter configuration

First: web.xml configuration

<filter>
	<filter-name>filterDemo1</filter-name>
	<filter-class>package cn.ideal.web.filter.FilterDemo1</filter-class>
</filter>

<filter-mapping>
	<filter-name>filterDemo1</filter-name>
	<!-- Intercept Path -->
	<url-pattern>/*</url-pattern>
</filter-mapping>

filter

<filter-name></filter-name>: Specify filter name

<filter-class></filter-class>: Specify the filter full class name (with package name)

filter-mapping

<filter-name></filter-name>: The label here is to correspond to the name in the filter above and point to the corresponding file

<url-pattern></url-pattern>: Set the path blocked by the filter_This determines what resources will be blocked by the filter

Intercept Path Settings

format explain
/test.jsp Filters will only be executed if the resource test.jsp is accessed
/test/* Execute filters when accessing all resources under test
*.jsp Execute filters when all jsp-formatted resources are accessed
/* Execute filters when any resource is accessed

Since some of the settings in the filter are more general, the format /* is generally used, but you can also choose one based on your needs.

Intercept configuration: dispatcher

Intercept configuration is also the form in which resources are accessed. There are several properties

  • REQUEST: Default, browser requests resources directly

  • FORWARD: Forward access to resources: RequestDispatcher.forward();

  • INCLUDE: Contains access to resources: RequestDispatcher.include();

  • ERROR: Error jumping resource: when called by declarative exception handling mechanism

Plus: Declarative exception handling means configuring in web.xml to determine how different exception types will be handled and ultimately jumping to which page, some of the 404 error pages we often see

<error-page>
  	<!--Exception Class-->
         <exception-type>xxx</exception-type>
  	<!--Pages that jump when an exception occurs-->
        <location>xxx</location>
</error-page>

Second: Configure using annotations

Similar to a servlet configuration, we can specify its name and intercept path

@WebFilter("filterName="FilterDemo1",urlPatters="/*")

But declare the comment directly on the class, obviously we don't need to specify its name, and by looking at the source, we know that urlPatters can be specified by value, and value can be omitted, so we can abbreviate it as

@WebFilter("/*")

To configure dispatcher in the filter comment, we need to set the dispatcher Types property

@WebFilter(value = "/*",dispatcherTypes ={DispatcherType.FORWARD,DispatcherType.FORWARD} )

(4) Life cycle of filters

Having finished configuring, let's go back to the topic and talk about the lifecycle of filters, which are the methods that are overridden to implement interfaces above.

The first is the init(FilterConfig config) method and the void destroy() method, which are also used by Servlet s, which are created and destroyed at server startup and shutdown, and which are executed once to load and release resources

In fact, these two methods are very understandable on the basis of Servlet.

Another is the core method of our filter:

void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)

The doFilter method is what we actually intercept. From the first two parameters, we know that we can filter whether Request or Respone, so what does the third parameter mean?

Let's open the source for FilterChain

public interface FilterChain {
    void doFilter(ServletRequest var1, ServletResponse var2) throws IOException, ServletException;
}

Hmm!FilterChain is an interface, and there is also a doFilter method defined within the interface. What is the meaning of its existence?

This is a chain structure, which we call filter chains here, and its purpose is to configure multiple filters, and the execution process under multiple filters is like this

So who's in front of and behind multiple filters?This is also related to our previous configuration

  • Annotation Configuration: Comparing class name strings with smaller values first
    • Eg:AFilterDemo takes precedence over BFilterDemo
  • web.xml configuration: <filter-mapping>who is on top and who is executing first

Simple execution process for filters

  • Execute filter

  • The resource that executes the release may be the next filter or a web resource (JSP/Servlet)

  • Execute the filter release code chain.doFilter(req, resp); code below

(5) Application of Filter

(1) Verification of login rights

Our previous knowledge can easily satisfy our login and simple registration implementation, but if we know the address and access some resources directly through the url, this is obviously unreasonable, so we need to verify the login status, and forward to the login interface if we are not logged in, then login canFree access to some pages based on login status

We wrote a simple simulation program. For readability and length issues, we omitted the part of the database connection and used a fixed password

This is the index.jsp page, which means you need to log in before you can release access

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>$Title$</title>
</head>
<body>
<h1>This is the first page. You will not be able to view it until you sign in.</h1>
</body>
</html>

This is the login.jsp page, the login page, which is very simple

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="/web-test/loginServlet" method="post">
    <table>
        <tr>
            <td>User name:</td>
            <td><input type="text" name="username"></td>
        </tr>
        <tr>
            <td>Password:</td>
            <td><input type="password" name="password"></td>
        </tr>
        <tr>
            <td><input type="submit" value="Sign in"></td>
        </tr>
    </table>
</form>
</body>
</html>

We create a domain package, write a User entity, and supplement its get, set methods

package cn.ideal.domain;

public class User {
    private String username;
    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

Start writing the LoginServlet, which is the code to handle login validation issues

package cn.ideal.web.servlet;

import cn.ideal.dao.UserDao;
import cn.ideal.domain.User;

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.io.IOException;

@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //Set Encoding
        request.setCharacterEncoding("utf-8");

        //Get Request Parameters
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        //Encapsulate user object
        User loginUser = new User();
        loginUser.setUsername(username);
        loginUser.setPassword(password);

        UserDao dao = new UserDao();
        User user = dao.login(loginUser);

        if (user == null){
            //Logon Failure
            request.getRequestDispatcher("/failServlet").forward(request,response);
        }else{
            //Login Successful
            request.getSession().setAttribute("user",user);
            request.getRequestDispatcher("/index.jsp").forward(request,response);
        }

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}

Let's tell if the username password is correct based on whether user equals null, so let's write down the login method that returns a User object

We create a UserDao class in the dao layer, formal items are written as interfaces, implementations are rewritten in the impl layer, to disguise our simplification

package cn.ideal.dao;

import cn.ideal.domain.User;

public class UserDao {
    public User login(User loginUser) {
        //Define a real user name password (instead of reading from the database)
        String trueUsername = "admin";
        String truePassword = "admin";

        if (loginUser.getUsername().equals(trueUsername) && loginUser.getPassword().equals(truePassword)) {
            //Landing Success
            return loginUser;
        } else {
            return null;
        }
    }
}

The key, which is what we're talking about here as a filter method, is to remember to write to the state when the login is successful

request.getSession().setAttribute("user",user);

package cn.ideal.web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter("/*")
public class LoginFilter implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        //Get Resource Request Path
        String requestURI = request.getRequestURI();

        //Exclude and grant access to resources that are really needed for login
        if (requestURI.contains("/login.jsp") || requestURI.contains("/loginServlet")) {
            chain.doFilter(request,response);
        }else{
            //Does not include, that is, verify that the user is logged in
            Object user = request.getSession().getAttribute("user");
            if (user != null){
                //Logged on, let go
                chain.doFilter(request,response);
            }else{
                //No login, jump back to login page
                request.getRequestDispatcher("/login.jsp").forward(request,response);
            }
        }
    }

    public void init(FilterConfig config) throws ServletException {
    }
}

(2) Sensitive word filtering

If we want to filter some of the information submitted by users, writing some code in the servlet is also a way to do it, but fiter is the most appropriate and more versatile. Let's use proxy mode to enhance request s and filter sensitive words with filter

We've just modified it on the index page

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>$Title$</title>
</head>
<body>
<h1>This is the first page. You will not be able to view it until you sign in.</h1>
<form action="/web-test/replaceServlet" method="post">
    <table>
        <tr>
            <td><input type="text" name="words"></td>
        </tr>
        <tr>
            <td><input type="submit" value="Sensitive Word Detection"></td>
        </tr>
    </table>
</form>
</body>
</html>

We read in the parameters passed in

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        String words = request.getParameter("words");
        System.out.println(words);
    }
package cn.ideal.web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.*;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

@WebFilter("/*")
public class ReplaceFilter implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //Create proxy objects to enhance getParameter
        ServletRequest proxy_req = (ServletRequest) Proxy.newProxyInstance(req.getClass().getClassLoader(), req.getClass().getInterfaces(), new InvocationHandler() {

            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //Determine if getParameter method
                if (method.getName().equals("getParameter")){
                    //Get Return Value
                    String value = (String)method.invoke(req, args);
                    if (value != null){
                        for (String s : list){
                            if (value.contains(s)){
                                value = value.replaceAll(s,"***");
                            }
                        }
                    }
                    return value;
                }
                return method.invoke(req,args);
            }
        });
        chain.doFilter(proxy_req, resp);
    }

    private List<String> list = new ArrayList<String>();

    public void init(FilterConfig config) throws ServletException {

        try {
            //Get the true path to the file
            ServletContext servletContext = config.getServletContext();
            String realPath = servletContext.getRealPath("/WEB-INF/classes/replace.txt");
            //read file
            BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(realPath),"UTF-8"));
            //Add each row of data to the list
            String line = null;
            while((line = br.readLine())!=null){
                list.add(line);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Ending:

If there are any inadequacies or errors in the content, you are welcome to leave a message for me, Crab and Crab!^^

If you can help, pay attention to me!(The series will be updated at the first time on Public Number)

We don't know each other here, but we are working hard for our dreams.

A public slogan insisting on the original Java technology: more than 20 years

Posted by Joopy on Mon, 09 Sep 2019 20:02:56 -0700