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