防盗链之基于springboot过滤器实现
什么是盗链
内容不在自己的服务器上,通过技术手段将其他网站的内容(图片,音乐,软件等) 放置在自己的网站中,通过这种方式盗取其他网站的空间和流量,减轻自己服务器的负担。
举个例子我们服务器上有一个播放视频的地址,其他的网站用户就可以将我们的视频地址引用到他们的网站上,他们服务器实际没有任何开销,却能以此吸引用户!
防盗链的原理
根本原理是基于HTTP协议中的Referer请求头,当浏览器向web服务器发送请求时, 一般会带上Referer请求头,告诉服务器请求时从哪个页面链接过来的,服务器以此可以获得一部分信息用于处理。
比如在我们的博客上放一个友情链接,他便能通过Referer来统计出每天有多少用户是通过我们的友链来访问他的网站。所以我们也能通过referer请求头来判断我们的链接是否被盗用。
注: 有时候一个http请求中是没有referer请求头的,例如直接在浏览器地址栏输入一个url;根据Referer的定义,他的作用是指示一个请求是从哪里链接过来,那么当请求并不是链接触发产生的,那么自然也就不需要指定referer请求头信息。
防盗链实现
防盗链的实现方式有很多种,这里我们主要介绍springboot中防盗链的实现,因为我们的接口程序也有一些是需要对外开放的,但是我们并不想或者是说想更自由的去处理防盗链。springboot中也有很多种方式实现此功能,过滤器,拦截器,切面等等,
但是我更推荐使用过滤器来实现,因为所有请求最先进入的就是过滤器。具体实现逻辑就是使用过滤器实现,具体逻辑请参考我们的代码。
实现代码
- 创建防盗链过滤器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
| import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.http.HttpStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType;
import javax.servlet.FilterConfig; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.HashMap; import java.util.Map;
public class RefererFilter implements Filter { private Logger log = LoggerFactory.getLogger(RefererFilter.class);
public static final String REFERER_WHITE_KEY = "refererWhiteKey"; private String[] refererWhite;
@Override public void init(FilterConfig filterConfig) { String refererWhites = filterConfig.getInitParameter(REFERER_WHITE_KEY); if (refererWhites != null && !"".equals(refererWhites)) { refererWhite = refererWhites.split(","); } }
@Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
if (isSafe((HttpServletRequest) servletRequest)) { filterChain.doFilter(servletRequest, servletResponse); } else { handleResponse((HttpServletResponse) servletResponse); }
}
@Override public void destroy() {
}
private boolean isSafe(HttpServletRequest request) { if (refererWhite == null || refererWhite.length < 1) { return true; } String referer = request.getHeader("referer"); if (referer == null || "".equals(referer)) { return false; } for (String white : refererWhite) { if (white.contains("*.")) { white = white.replace("*.", ""); } if (referer.contains(white)) { return true; } } return false; }
public void handleResponse(HttpServletResponse response) { try { Map<String, String> resultMsg = new HashMap<>(); resultMsg.put("code", String.valueOf(HttpStatus.SC_FORBIDDEN)); resultMsg.put("msg", "资源不允许"); ObjectMapper objectMapper = new ObjectMapper(); String msg = objectMapper.writeValueAsString(resultMsg); response.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE); response.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR); response.getWriter().write(msg); } catch (IOException e) { log.error("防盗链过滤器处理response失败", e); } }
}
|
- 配置过滤器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered;
import java.util.HashMap; import java.util.Map;
@Configuration public class FilterConfig {
@Bean public FilterRegistrationBean<RefererFilter> registrationRefererFilter() { RefererFilter refererFilter = new RefererFilter(); FilterRegistrationBean<RefererFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setName(RefererFilter.class.getName()); registrationBean.setFilter(refererFilter); registrationBean.addUrlPatterns("/*"); Map<String, String> initParam = new HashMap<>(); initParam.put(RefererFilter.REFERER_WHITE_KEY, "www.baidu.com,www.qq.com"); registrationBean.setInitParameters(initParam); registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE); return registrationBean; } }
|
总结
我这里讲的是最简单的防盗链,现实情况时还有很多反防盗链,要做到绝对的防盗链还是要根据实际使用情况结合自身情况出发。