SpringBoot實(shí)現(xiàn)文章防盜鏈的代碼設(shè)計(jì)
來今天的正題:springboot實(shí)現(xiàn)圖片防盜鏈??赡芸雌饋韴?chǎng)景比較抽象,這里shigen給出之前的一個(gè)例子:對(duì)象存儲(chǔ)服務(wù)的流量被盜刷了,當(dāng)時(shí)官方給的解決方案包括我后來采用的方式就是referer的限制。

后來我的對(duì)象存儲(chǔ)服務(wù)的流量就正常了。那今天我也是好奇這個(gè)用springboot怎么實(shí)現(xiàn)。在接下來的內(nèi)容中,我將會(huì)著重分享我的設(shè)計(jì)。
首先了解一下Referer是什么吧。
什么是Referer
這里告別充滿廣告和垃圾網(wǎng)站的搜索引擎,直接GPT查詢:
Referer(來源)是HTTP頭部字段之一,用于指示客戶端是從哪個(gè)頁面跳轉(zhuǎn)或發(fā)起請(qǐng)求的。當(dāng)客戶端(通常是瀏覽器)向服務(wù)器發(fā)送請(qǐng)求時(shí),它會(huì)在HTTP頭部中包含 Referer 字段,告訴服務(wù)器請(qǐng)求的來源頁面的URL。這個(gè)字段可以幫助服務(wù)器了解請(qǐng)求的上下文和用戶行為,有助于進(jìn)行數(shù)據(jù)分析、安全檢查等操作。
也就是說請(qǐng)求一個(gè)資源的時(shí)候,瀏覽器的請(qǐng)求頭信息中會(huì)帶上Referer字段標(biāo)示出當(dāng)下的請(qǐng)求的上一個(gè)請(qǐng)求是什么地方來的。
那基于這個(gè)原理,我們就可以設(shè)計(jì)出自己的防盜鏈。
java代碼的設(shè)計(jì)
基礎(chǔ)版
假設(shè)我們的springboot項(xiàng)目中可以直接通過http請(qǐng)求訪問到某個(gè)路徑下的資源。我們先這樣的嘗試吧。我們的配置肯定要實(shí)現(xiàn)WebMvcConfigurer這個(gè)接口,實(shí)現(xiàn)資源的映射。那我就直接展示我的代碼:
@Configuration
@EnableWebMvc
@Slf4j
public class MvcConfig implements WebMvcConfigurer {
?
/**
* 靜態(tài)資源保存目錄
*/
public static final String FILE_RESOURCE_PATH = "file:" + System.getProperty("user.dir") + "/files/";
?
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
log.error("靜態(tài)資源保存目錄:{}", FILE_RESOURCE_PATH);
registry.addResourceHandler("/files/**")
.addResourceLocations(FILE_RESOURCE_PATH);
}
}
其實(shí)我們最終實(shí)現(xiàn)的文件路徑就是項(xiàng)目根路徑/files/文件夾的全部文件。
這樣我們就可以通過http請(qǐng)求訪問了。

但是,明顯的我們的資源不是很安全。因?yàn)槿我鈦碓?、任何人都可以訪問到它。那我們限制來源的話,這個(gè)時(shí)候Referer就可以派上用場(chǎng)了。
升級(jí)版
升級(jí)版本,我們就需要統(tǒng)一攔截一下請(qǐng)求,看看請(qǐng)求頭中是否包含Referer信息,且是我們約定的Referer。這樣才能判定是正常的請(qǐng)求,進(jìn)行流量的放行,否則的話就是要去攔截。
接下來先去設(shè)計(jì)一個(gè)攔截器:
@Slf4j
@Component
public class ResourceInterceptor extends HandlerInterceptorAdapter {
?
@Resource
private ReferConfig referConfig;
?
/**
* 匹配的文件種類
*/
private static final String FILE_REGEX = "\.(html|css|js|jpg|jpeg|png|gif|bmp|svg|pdf|doc|docx|xls|xlsx|ppt|pptx|mp4|mov)$";
private static final Pattern FILE_REGEX_PATTERN = Pattern.compile(FILE_REGEX, Pattern.CASE_INSENSITIVE);
?
?
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 獲取請(qǐng)求的 URL
String requestUrl = request.getRequestURL().toString();
log.info("requestUrl:{}", requestUrl);
// 檢查是否是靜態(tài)資源請(qǐng)求
if (referConfig.isEnabled() && isStaticResource(requestUrl)) {
// 檢查防盜鏈策略
if (!isValidReferer(request)) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
return false;
}
}
return true;
}
?
/**
* 正則驗(yàn)證請(qǐng)求的資源
*
* @param url 請(qǐng)求資源
* @return 是否匹配
*/
private boolean isStaticResource(String url) {
return FILE_REGEX_PATTERN.matcher(url).find();
}
?
/**
* 檢查 Referer 頭,判斷請(qǐng)求是否合法
*
* @param request 請(qǐng)求
* @return 是否是合法請(qǐng)求
*/
private boolean isValidReferer(HttpServletRequest request) {
String referer = request.getHeader("Referer");
return CollectionUtil.contains(referConfig.getAllowedOrigins(), referer);
}
}
具體的業(yè)務(wù)邏輯的驗(yàn)證都在注釋里,這里需要注意:
- 關(guān)于
Referer的配置最好寫成動(dòng)態(tài)的,便于后期的拓展 - 對(duì)于url的請(qǐng)求判斷最好使用正則表達(dá)式,因?yàn)閡rl本身請(qǐng)求的就是靜態(tài)資源,但是后邊帶了其他的參數(shù)可能導(dǎo)致直接繞過
對(duì)于自定的配置類,shigen是這樣的設(shè)計(jì):
@Configuration
@ConfigurationProperties(prefix = "refer")
@Data
public class ReferConfig {
/**
* 是否開啟防盜鏈攔截
*/
private boolean enabled;
/**
* 允許的Referer請(qǐng)求
*/
private List<String> allowedOrigins;
?
}
接下來就是配置到攔截器上。
@Configuration
@EnableWebMvc
@Slf4j
public class MvcConfig implements WebMvcConfigurer {
?
@Resource
private UserArgumentResolver userArgumentResolver;
?
@Resource
private ResourceInterceptor resourceInterceptor;
?
/**
* 靜態(tài)資源保存目錄
*/
public static final String FILE_RESOURCE_PATH = "file:" + System.getProperty("user.dir") + "/files/";
?
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(userArgumentResolver);
}
?
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(resourceInterceptor).addPathPatterns("/**");
}
?
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
log.error("靜態(tài)資源保存目錄:{}", FILE_RESOURCE_PATH);
registry.addResourceHandler("/files/**")
.addResourceLocations(FILE_RESOURCE_PATH);
}
}
待一切完成,我們這里再檢查一下配置文件就可以正常的啟動(dòng)服務(wù)進(jìn)行測(cè)試了。
refer:
enabled: true
allowed-origins:
- http://www.shigen.com
此時(shí),我們?cè)俅卧跒g覽器中直接訪問:

這時(shí)我們想要正常的訪問,就得借助于接口測(cè)試工具了。

以上就是SpringBoot實(shí)現(xiàn)文章防盜鏈的代碼設(shè)計(jì)的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot文章防盜鏈的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Spring Boot應(yīng)用發(fā)布到Docker的實(shí)現(xiàn)
這篇文章主要介紹了Spring Boot應(yīng)用發(fā)布到Docker的實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-06-06
Java設(shè)計(jì)模式以虹貓藍(lán)兔的故事講解適配器模式
適配器模式(Adapter?Pattern)是作為兩個(gè)不兼容的接口之間的橋梁。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它結(jié)合了兩個(gè)獨(dú)立接口的功能2022-04-04
linux系統(tǒng)下java項(xiàng)目在后臺(tái)啟動(dòng)的4種方式總結(jié)
Linux是集多種功能于一身的操作系統(tǒng),它可以讓用戶查看和管理當(dāng)下正在運(yùn)行的進(jìn)程,包括Java程序,這篇文章主要給大家總結(jié)介紹了關(guān)于linux系統(tǒng)下java項(xiàng)目在后臺(tái)啟動(dòng)的4種方式,需要的朋友可以參考下2023-10-10
Java基礎(chǔ)學(xué)習(xí)筆記之?dāng)?shù)組詳解
這篇文章主要介紹了Java基礎(chǔ)學(xué)習(xí)筆記之?dāng)?shù)組,結(jié)合實(shí)例形式詳細(xì)分析了java的基本概念、定義、迭代、輸出、反轉(zhuǎn)、排序等常用操作技巧,需要的朋友可以參考下2019-08-08
java的Jackson將json字符串轉(zhuǎn)換成泛型List
這篇文章主要介紹了java的Jackson將json字符串轉(zhuǎn)換成泛型List ,這里整理了詳細(xì)的代碼,有需要的小伙伴可以參考下。2017-02-02

