1. 程式人生 > 其它 >Filter的應用--許可權管理和過濾敏感詞彙

Filter的應用--許可權管理和過濾敏感詞彙

技術標籤:Java web過濾器java

剛剛做了一個關於Filter的應用,趁著腦熱趕緊記錄下來,此篇一共是有兩個小應用一個是關於許可權管理,*什麼是許可權管理呢?*就是當你沒有登入的時候你不能做任何事情,這個操作很眼熟,例如天貓的下單系統,當你沒有登入的時候只能瀏覽,並不能提交訂單和付款,當你提交訂單的時候會提醒你先登入。還有一個常見的例子就是一些網站的登入查詢系統,當你沒有登入的時候是不能檢視任何資訊的,這就是許可權管理,這樣做的好處就是很安全,過濾掉了一些不安全的因素,一般現在只要是涉及到登陸的網站基本都是用了過濾器來實現這個許可權管理操作的。另一個小應用就是過濾敏感詞彙,這個應用就更常見了,這個例子隨處可見,例如在王者峽谷,你是祖安人,然後對面很菜,或者是說你也很菜,對面在噴你,然後你發揮祖安人的良好血統,開始對噴,這時候你會發現聊天框裡就會出現"我 **

* **" 大量的我,你,還有星號,這就是做了敏感詞彙過濾操作,接下來我們重點實現以下敏感詞彙過濾。
關於許可權管理,其實實現起來很簡單,大體思想就是先看你要訪問的資源是否是與登入有關的例如login.jsp這樣的資源就不會過濾掉,然後咱判斷你是否已經登陸了,是否已經登入是通過session來判斷的,當你登陸成功之後你會在session裡面存一個引數,在過濾器裡面驗證這個引數是否存在就可以了,當你當開啟瀏覽器還沒有登入的時候這個引數肯定是空的,這時節如果你要訪問別的資源就會被攔截,過濾器的程式碼如下:

 @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //強制轉換
        HttpServletRequest request = (HttpServletRequest) req;

        //獲取請求的資源路徑 看是否是登入相關的資源
        String uri = request.getRequestURI();

        //判斷
        if (uri.contains("/index.jsp") || uri.contains("/UserLoginServlet") ||uri.contains("/JSP/css/") || uri.contains("/JSP/js/")){
            //包含 證明使用者就是想登陸 放行
            chain.doFilter(req, resp);
        }else{
            //不包含 驗證使用者是否已經登入
            if (request.getSession().getAttribute("user") != null){
                //已經登陸 放行
                chain.doFilter(req, resp);
            }else {
                System.out.println("您被攔截了,您需要先登入" );
                request.setAttribute("longinmessage","您尚未登入,請先登入!");
                request.getRequestDispatcher("/index.jsp").forward(request, resp);
            }
        }
    }

然後我們重點來說一下實現敏感詞彙遮蔽的操作,這個操作思路上很簡單,就是有一個txt檔案,裡面放著各種敏感詞彙,一行一個敏感詞。當你呼叫方法輸入帶有敏感詞的語句的時候就會把敏感詞來替換成星號,這個替換的操作在request的方法裡面沒有可以實現這個功能的,所以我們需要用到一個代理模式,這個才是麻煩的地方,*為什麼要用代理模式呢?*比如我們呼叫request.getParameter("name");這條語句,我們給name賦值,但是這個方法本身並不支援替換敏感字元,需要我們增強一個這個方法的功能,讓他呼叫的時候可以實現替換掉敏感詞。
那我們先來說什麼是代理模式?
代理模式可以做到增強一些方法的功能,就像是剛才上面說的給某個方法增強過濾功能,以後呼叫這個方法的時候就會過濾掉一些敏感詞,增強方法功能的設計模式呢還有一個叫裝飾者模式

,這兩個都可以實現增強方法的功能。代理模式顧名思義,具有代理商的一種模式,有代理肯定就有真實的大老闆,代理商從大老闆那裡拿貨,就像是我們日常生活中的例子,很多賣鞋的,莆田貨居多,在莆田有很多大牛,然後他們手下有很多代理商,我們買鞋都是通過代理商,而不是直接找大老闆。比如大老闆賣這雙鞋子是八百,通過代理商我成功入手價格是900,代理商增強了價格,含淚賺了我一百塊錢。那我們為什麼不直接找大老闆呢?因為代價太大,或者是找不到大老闆,所以我們只能通過代理商來拿貨。這樣來講代理模式就明白許多了吧,代理商代理大老闆,我們從代理商那裡拿貨,並達到從大老闆那裡拿貨的目的
我們通過一個簡單的例子來說明一下,我們先新建一個介面,不管是代理商還是大老闆都是賣鞋的,我們需要有一個介面來說明相關的方法:

package proxy;

/**
 * @author Shi Jun Yi
 * @version 1.0
 * @date 2021/1/25 12:32
 */
public interface SaleComputer {

    public String sale(double money);

    public void show();
}

有了這個介面之後我們就要有一個真實的大老闆物件

package proxy;

/**
 * @author Shi Jun Yi
 * @version 1.0
 * @date 2021/1/25 12:34
 */
public class Lenovo implements SaleComputer {
    @Override
    public String sale(double money) {
        System.out.println("花了"+money+"元買了一雙回到未來....");
        return "耐克鞋子";
    }

    @Override
    public void show() {
        System.out.println("展示鞋子.....");
    }
}

接下里我們寫一個測試類:

package proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author Shi Jun Yi
 * @version 1.0
 * @date 2021/1/25 12:35
 */
public class ProxyTest {

    public static void main(String[] args ){
        //建立真實物件
        Lenovo lenovo = new Lenovo();

        //動態代理 增強lenovo物件
        /*
            三個引數
                類載入器 真實物件
                介面陣列 真實物件
                處理器 很重要 核心業務邏輯
         */
        SaleComputer proxy_lenovo = (SaleComputer) Proxy.newProxyInstance(lenovo.getClass().getClassLoader(), lenovo.getClass().getInterfaces(), new InvocationHandler() {
            /*
                代理邏輯 代理物件呼叫的所有的方法都會觸發該方法
                    引數
                        1 代理物件
                        2 代理物件呼叫的方法
                        3 呼叫物件的時候傳遞的引數
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
               /* System.out.println("該方法被執行了......");
                System.out.println(method.getName());
                System.out.println(args[0]);*/

               //使用真實物件的方法呼叫該方法

                if(method.getName().equals("sale")){
                    //增強引數
                    double money = (double)args[0];
                    money = money*0.85;
                    System.out.println("專車接....");
                    String obj = (String) method.invoke(lenovo, money);
                    System.out.println("專車送....");
                    //增強返回值
                    return obj+"_鞋墊";
                }else{
                    Object obj = method.invoke(lenovo,args);
                    return obj;
                }
            }
        });

        //呼叫方法
        String computer = proxy_lenovo.sale(80000);

        System.out.println(computer);
    }
}

在這裡插入圖片描述
然後我們來說一下大致的實現步驟:

  1. 既然是代理模式 那我們肯定是要對真實物件進行代理 所以我們new一個真實物件。
  2. 通過固定的格式Proxy.newProxyInstance(....)格式來實現對真實物件的代理,在這個方法裡面有一個重寫過的invoke方法,這裡面放的是核心的增強邏輯,代理邏輯 代理物件呼叫的所有的方法都會觸發該方法。
  3. 這個invoke方法裡面有三個引數,第一個引數是代理物件,第二個引數是代理物件呼叫的方法,代理物件呼叫方法時傳的引數。
  4. String computer = proxy_lenovo.sale(80000);由於我們呼叫的是sale方法,所以我們就需要判斷方法名是不是sale,如果是的話就會增強返回值,如果不是就預設執行方法。這個增強方法的實現,其實就是把原先沒有增強的方法先執行一下,然後對沒有增強的返回值加上一些內容,將新的返回值返回,以達到增強方法的效果。
  5. 當我們代理物件呼叫的方法是sale的時候會把引數先傳過來,然後將這個引數乘0.85,在執行真實物件的該方法並返回一個值,String obj = (String) method.invoke(lenovo, money);這句話就是呼叫真實物件方法的語句。得到了返回值,對返回值加上一些內容返回輸出就可以了。
    這就是一個簡單的實現。接下來我們再說回敏感詞彙的問題。
    首先我們先建立一個名為“敏感詞彙.txt”的檔案,內容如下:
    在這裡插入圖片描述
    一些極度祖安的話我就不說了,太敏感了,你們自行新增~
    首先我們新建一個過濾器名字就叫sesitivewordsfilter,我們自然是要在doFlter方法裡面進行字元過濾操作,一開始我們就建立一個代理物件,模式與上一樣,在做增強方法之前我們先要將敏感詞彙.txt檔案進行載入,初始化記載檔案應該放到init方法內,首先我們先要有一個存放敏感詞彙的集合private List<String> list = new ArrayList<>();在inti方法中有一個引數叫config,我們可以用config自帶的config.getServletContext().getRealPath("敏感詞彙.txt");方法載入檔案,載入好之後進行讀取,我們用到了IO流的知識,用一個帶緩衝區的檔案讀取檔案BufferedReader br = new BufferedReader(new FileReader(contextPath)); ,然後將檔案的每一行加入到集合當中,當檔案讀完了就關閉該流,這樣一來我們的所有敏感詞就全部存到了list集合當中了,到時候我們只需要對比是否包含就可以了。我們先對request的getParameter方法進行增強,第一步我們要做的肯定是要判斷是否是該方法,通過引數列表裡面自帶的method.getName();來返回方法名,然後先執行原先的getPramenter方法,將其值返回,返回之後如果返回值不為空,那麼遍歷list結合,檢視返回值是否包含list集合當中的敏感詞,如果包含替換成星號。如果不是呼叫的getParamenter方法,就返回原先的引數return method.invoke(req,args);,最後通過chain.doFilter(proxy_req, resp);返回增強之後的request。
    過濾器程式碼:
package filter;

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

/**
 * @author Shi Jun Yi
 * @version 1.0
 * @date 2021/1/25 15:03
 * 敏感詞彙過濾器
 */
@WebFilter(filterName = "SensitiveWordsFilter", value = "/TestServlet")
public class SensitiveWordsFilter implements Filter {
    @Override
    public void destroy() {

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //建立代理物件 增強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 {
                //增強方法 先判斷是否是該方法
                if (method.getName().equals("getParameter")){
                    //增強返回值
                    String value = (String)method.invoke(req, args);
                    if (value != null){
                        for (String str:list) {
                            if (value.contains(str)){
                                value = value.replaceAll(str,"***");
                            }
                        }
                    }
                    return value;
                }

                //增強getAttribute方法
                if (method.getName().equals("getAttribute")){
                    //增強返回值
                    String value = (String) method.invoke(req, args);
                    if (value != null){
                        for (String str:list) {
                            if (value.contains(str)){
                                value = value.replaceAll(str,"**");
                            }
                        }
                    }
                    return value;
                }

                return method.invoke(req,args);
            }
        });

        //放行增強後的request方法
        chain.doFilter(proxy_req, resp);
    }

    //放敏感詞彙集合
    private List<String> list = new ArrayList<>();

    @Override
    public void init(FilterConfig config) throws ServletException {

        try{
        //載入檔案
            String contextPath = config.getServletContext().getRealPath("敏感詞彙.txt");

            //讀取檔案
            BufferedReader br = new BufferedReader(new FileReader(contextPath));

            //將檔案的每一行新增到list當中
            String line = null;
            while ((line = br.readLine()) != null){
                list.add(line);
             }
             br.close();
            System.out.println(list);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

}

我們新建一個servlet來呼叫一下增強後的方法,

package control;

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;

/**
 * @author Shi Jun Yi
 * @version 1.0
 * @date 2021/1/25 15:33
 */
@WebServlet(name = "TestServlet", value = "/TestServlet")
public class TestServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String name = request.getParameter("name");
        String msg = request.getParameter("msg");

        request.setAttribute("name2", "我diu,你這個大笨蛋,大SB...");
        System.out.println(request.getAttribute("name2"));

        System.out.println(name+":"+msg);
    }

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

接下來我們檢視效果:
在這裡插入圖片描述
在這裡插入圖片描述
效果還不錯,hhh~~,以上就是這篇部落格所要展示的內容,如有不足之處,還請指出,謝謝。

參考內容:https://www.bilibili.com/video/BV1u7411Z769?p=12