
I. Các tình huống
1. Người dùng yêu cầu một trang web , một request sẽ gửi tới server , nó phải đi qua bộ lọc(Filter) trước khi tới trang yêu cầu
2.Tuy nhiên các request không vượt qua được hết các tầng Filter
3. Tình huống người dùng gửi một yêu cầu một trang(page1) yêu cầu này sẽ phải vượt qua các Filter , tại một filter nào đó yêu cầu bị chuyển hướng sang một trang khác(page2)
Trong bài này chúng ta sẽ nói về Servlet Filter trong Java.Cách sử dụng khác nhau của servlet filters , tạo bộ lọc và tìm hiểu cách sử dụng của nó trên web đơn giản.
II. Tại sao chúng ta phải dùng Servlet Filter
- Đảm bảo rằng tài nguyên chỉ có thể truy cập được khi phiên người dùng hợp lệ bằng cách sử dụng session attributes
- Servlet Filter sử dụng chặn một yêu cầu và tiến hành xử lý trước hoặc xử lý sau đối với yêu cầu đó.Nó hữu ích trong việc triển khai các tính năng
- Logging of requests(Ghi nhật ký các yêu cầu)
- Xác thực và phân quyền các request yêu cầu
- Định dạng request body or header trước khi gửi đến servlet
- Encryption or Decryption
- Thay đổi phản hồi bằng cách thêm một số cookie, thông tin tiêu đề,…
III. Servlet filters
Servlet filters cấu hình trong file (web.xml) và cài đặt sử dụng thư viện ,thêm hoặc xóa bộ lọc servlet chỉ bằng cách chỉnh sửa web.xml
Có thể tạo nhiều Servlet filters ,và tạo một chuỗi các bộ lọc tài nguyên trong web.xml, ta có thể tạo Servlet filter triển khai giao diện javax.servlet.Filter
Servlet filter interface: tương tự như giao diện Servlet và chúng ta cần triển khai nó để tạo bộ lọc servlet của riêng mình,chứa các phương thức vòng đời của Servlet filter và được quản lý bởi vùng chứa servlet
Servlet Filter interface vòng đời:
- void init(FilterConfig paramFilterConfig): Khi Servlet filter được khởi tạo là phương thức được gọi, phương thức chỉ được gọi một lần trong vòng đời của bộ lọc và chúng ta nên khởi tạo tài nguyên trong phương thức này. FilterConfig được sử dụng vùng chứa để cung cấp các tham số init và object servlet cho filter.
- doFilter(ServletRequest paramServletRequest ,ServletResponse paramServletResponse ,FilterChain paramFilterChain) : Phương thức gọi mỗi lần bởi vùng chứa khi nó phải áp dụng bộ lọc cho một tài nguyên, vùng chứa cung cấp các tham chiếu đối tượng yêu cầu và phản hồi để lọc dưới dạng đối số, FilterChain được sử dụng để gọi bộ lọc tiếp theo trong chuỗi.
- void destroy() : loại bỏ Filter gọi phương thức hủy ,phương pháp đóng bất kỳ tài nguyên nào được mở bởi bộ lọc, chỉ gọi một lần trong thời gian tồn tại của bộ lọc.
IV. Servlet WebFilter annotation
javax.servlet.annotation.WebFilter giới thiệu trong Servlet 3.0 ,ta có thể sử dụng annotation để khai báo một filter servlet. Chúng ta có thể sử dụng annotation để xác định các tham số init , tên bộ lọc và mô tả , các servlet, url ,các loại điều phối để áp dụng filter
V. Servlet Filter configuration in web.xml
Ta có thể khai báo servlet filter trong web.xml
<filter>
<filter-name>RequestLoggingFilter</filter-name> <!-- mandatory -->
<filter-class>com.journaldev.servlet.filters.RequestLoggingFilter</filter-class> <!-- mandatory -->
<init-param> <!-- optional -->
<param-name>test</param-name>
<param-value>testValue</param-value>
</init-param>
</filter>
Ta có thể ánh xạ servlet tới các class or mẫu url
<filter-mapping>
<filter-name>RequestLoggingFilter</filter-name> <!-- mandatory -->
<url-pattern>/*</url-pattern> <!-- either url-pattern or servlet-name is mandatory -->
<servlet-name>LoginServlet</servlet-name>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
Chú ý : Khi tạo Servlet filter, đầu tiên vùng chứa sẽ xử lý các mẫu url và sau đó là các tên servlet , vì vậy ta phải đảm bảo các servlet filter thực thi theo một thứ tự cụ thể chú ý trong khi xác định ánh xạ bộ lọc
VI. Servlet Filter example
Trong ví dụ về bộ lọc servlet ,chúng tôi sẽ tạo các bộ lọc để ghi nhật ký các thông số và cookie yêu cầu và xác thực phiên cho tất cả các tài nguyên
Login.html code :
<!DOCTYPE html>
<html>
<head>
<meta charset="US-ASCII">
<title>Login Page</title>
</head>
<body>
<form action="LoginServlet" method="post">
Username: <input type="text" name="user">
<br>
Password: <input type="password" name="pwd">
<br>
<input type="submit" value="Login">
</form>
</body>
</html>
LoginServlet
package com.journaldev.servlet.session;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private final String userID = "admin";
private final String password = "password";
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String user = request.getParameter("user");
String pwd = request.getParameter("pwd");
if(userID.equals(user) && password.equals(pwd)){
HttpSession session = request.getSession();
session.setAttribute("user", "Pankaj");
session.setMaxInactiveInterval(30*60);
Cookie userName = new Cookie("user", user);
userName.setMaxAge(30*60);
response.addCookie(userName);
response.sendRedirect("LoginSuccess.jsp");
}else{
RequestDispatcher rd = getServletContext().getRequestDispatcher("/login.html");
PrintWriter out= response.getWriter();
out.println("<font color=red>Either user name or password is wrong.</font>");
rd.include(request, response);
}
}
}
LoginSuccess.jps code:
<%@ page language="java" contentType="text/html; charset=US-ASCII"
pageEncoding="US-ASCII"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Login Success Page</title>
</head>
<body>
<%
//allow access only if session exists
String user = (String) session.getAttribute("user");
String userName = null;
String sessionID = null;
Cookie[] cookies = request.getCookies();
if(cookies !=null){
for(Cookie cookie : cookies){
if(cookie.getName().equals("user")) userName = cookie.getValue();
if(cookie.getName().equals("JSESSIONID")) sessionID = cookie.getValue();
}
}
%>
<h3>Hi <%=userName %>, Login successful. Your Session ID=<%=sessionID %></h3>
<br>
User=<%=user %>
<br>
<a href="CheckoutPage.jsp">Checkout Page</a>
<form action="LogoutServlet" method="post">
<input type="submit" value="Logout" >
</form>
</body>
</html>
CheckoutPage.jsp code
<%@ page language="java" contentType="text/html; charset=US-ASCII"
pageEncoding="US-ASCII"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Login Success Page</title>
</head>
<body>
<%
String userName = null;
String sessionID = null;
Cookie[] cookies = request.getCookies();
if(cookies !=null){
for(Cookie cookie : cookies){
if(cookie.getName().equals("user")) userName = cookie.getValue();
}
}
%>
<h3>Hi <%=userName %>, do the checkout.</h3>
<br>
<form action="LogoutServlet" method="post">
<input type="submit" value="Logout" >
</form>
</body>
</html>
LogoutServlet
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Servlet implementation class LogoutServlet
*/
@WebServlet("/LogoutServlet")
public class LogoutServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
Cookie[] cookies = request.getCookies();
if(cookies != null){
for(Cookie cookie : cookies){
if(cookie.getName().equals("JSESSIONID")){
System.out.println("JSESSIONID="+cookie.getValue());
break;
}
}
}
//invalidate the session if exists
HttpSession session = request.getSession(false);
System.out.println("User="+session.getAttribute("user"));
if(session != null){
session.invalidate();
}
response.sendRedirect("login.html");
}
}
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@WebFilter("/AuthenticationFilter")
public class AuthenticationFilter implements Filter {
private ServletContext context;
public void init(FilterConfig fConfig) throws ServletException {
this.context = fConfig.getServletContext();
this.context.log("AuthenticationFilter initialized");
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
String uri = req.getRequestURI();
this.context.log("Requested Resource::"+uri);
HttpSession session = req.getSession(false);
if(session == null && !(uri.endsWith("html") || uri.endsWith("LoginServlet"))){
this.context.log("Unauthorized access request");
res.sendRedirect("login.html");
}else{
chain.doFilter(request, response);
}
}
public void destroy() {
}
}
File web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://java.sun.com/xml/ns/javaee" xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<display-name>ServletFilterExample</display-name>
<welcome-file-list>
<welcome-file>login.html</welcome-file>
</welcome-file-list>
<filter>
<filter-name>RequestLoggingFilter</filter-name>
<filter-class>com.journaldev.servlet.filters.RequestLoggingFilter</filter-class>
</filter>
<filter>
<filter-name>AuthenticationFilter</filter-name>
<filter-class>com.journaldev.servlet.filters.AuthenticationFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>RequestLoggingFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>AuthenticationFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
Đoàn Văn Hiệu