防盜鏈概念詳解以及自己使用tomcat實現一個防盜鏈
最近在使用阿里雲OSS雲端儲存的時候接觸到了防盜鏈這麼一個概念。
我們先從什麼是防盜鏈開始講起。
假設我們有這樣一個場景。
張三同學有一個網站。網站的圖片資源是存放在阿里雲的OSS的雲端儲存上的。
我們知道如果我們將圖片或者視訊等檔案上傳到oss,我們可以得到一個url。我們可以通過得到的url來訪問該圖片或者是視訊資源。
那麼現在問題來了。有一個同學是李四。李四同學也架設了一個網站。並且,李四同學正愁沒有圖片和視訊資源供訪問者訪問的時候,發現了張三同學在阿里雲oss上儲存的資源。於是乎,就將分析得到的url統統用
<img>
標籤囊括到自己的網站下。訪客在訪問李四同學的網站時,看到的是李四同學的網站品牌。然而資料內容的實際提供者是張三同學。這時候張三同學就很冤啊,花了OSS儲存的流量的錢,卻沒有相應的使用者量。
所以現在有一個措施叫防盜鏈。
我們可以開啟阿里OSS儲存的控制檯去看看。
筆者這裡設定了只有http://localhost:63342地址開頭的才能請求對應的圖片或者視訊資源。
這樣就避免了李四同學去蹭張三同學的流量了。
好奇的同學可能會問了。這是什麼原理?
原理其實是比較簡單的。
他是根據Http請求頭的Referer欄位的值來決定的。
如
筆者某一次的請求的http請求頭的名值對是這樣的。
Accept:image/webp,image/,/*;q=0.8
Accept-Encoding:gzip, deflate, sdch
Accept-Language:zh-CN,zh;q=0.8,en;q=0.6
Connection:keep-alive
Host:banzhuannanzihan.oss-cn-shanghai.aliyuncs.com
Referer:
User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36
有的時候Referer欄位可能為空。
那麼既然如此我們可不可以自己在Tomcat上實現一個呢?
當然是可以的,而且實現起來很簡單。我們可以將邏輯寫到Tomcat的過濾器中。程式碼是這樣的
package org.huluo.filter;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
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 java.io.IOException;
@WebFilter(urlPatterns = "/*")
public class RefererFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("過濾器初始化");
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (request instanceof HttpServletRequest) {
System.out.println(((HttpServletRequest) request).getHeader("Referer"));
//如果請求的來源是 http://localhost:63342開頭的,則讓其從tomcat上載入圖片資源
if (((HttpServletRequest) request).getHeader("Referer") != null && ((HttpServletRequest) request).getHeader("Referer").startsWith("http://localhost:63342")) {
chain.doFilter(request, response);
} else {//如果不是則讓其無法載入圖片
System.out.println("不讓過得到圖片");
if (response instanceof HttpServletResponse) {
((HttpServletResponse) response).setStatus(403,"不讓載入圖片");
}
}
}
}
public void destroy() {
System.out.println("過濾器銷燬");
}
}