基于SpringBoot实现防盗链功能

 更新时间:2024年12月16日 17:11:05   作者:HBLOG  
防盗链是保护资源服务器的常用方法,旨在防止未经授权的外部链接直接访问服务器上的资源,如图片、音频和视频文件,在本文中,我们将探讨防盗链的概念和原理,并结合 Spring Boot 提供一个完整的可运行示例,需要的朋友可以参考下

一、防盗链概念

防盗链是一种通过限制资源访问来源的技术,通常通过检查 HTTP 请求头中的 Referer 字段来实现。如果请求的来源不是允许的域名,则拒绝该请求。除此之外,还可以结合 Token 和时间戳进一步提高安全性,确保链接只能在一定时间内有效。

二、防盗链原理

  • Referer 校验
    • HTTP Referer 是浏览器在发送请求时附加的字段,用于标明请求的来源页面。
    • 服务器可以通过检查 Referer 是否属于信任的域名,拒绝其他来源的访问请求。
  • Token 验证
    • 服务器为合法请求生成带签名的访问链接(包含 Token),客户端访问时携带该 Token。
    • 服务器通过验证 Token 是否正确来判断请求合法性。
  • 时间限制
    • 通过在请求中附带时间戳参数,限制链接的有效期。
    • 服务器校验请求的时间戳与当前时间的差值,超出范围的请求将被拒绝。

通过以上三种机制,可以显著提高资源防盗链的安全性。

三、项目结构

以下是示例项目的目录结构:

src
├── main
│   ├── java
│   │   └── com.demo
│   │       ├── DemoApplication.java
│   │       ├── filter
│   │       │   ├── StaticResourceFilter.java
│   │       │   ├── TokenValidator.java
│   │       │   └── TimeValidator.java
│   └── resources
│       └── static
│           └── images
                     └──711815.jpeg

四、核心代码实现

1. 主应用程序入口

package com.et;

import com.et.filter.StaticResourceFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class DemoApplication {

   public static void main(String[] args) {
      SpringApplication.run(DemoApplication.class, args);
   }
   @Bean
   public FilterRegistrationBean<StaticResourceFilter> staticResourceFilter() {
      FilterRegistrationBean<StaticResourceFilter> registrationBean = new FilterRegistrationBean<>();
      registrationBean.setFilter(new StaticResourceFilter());
      registrationBean.addUrlPatterns("/images/*");
      return registrationBean;
   }
}

2. 静态资源访问过滤器

package com.et.filter;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class StaticResourceFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        // validate Referer
        String referer = httpRequest.getHeader("Referer");
        String allowedDomain = "http://localhost:8088";
        if (referer == null || !referer.startsWith(allowedDomain)) {
            httpResponse.getWriter().write("403 Forbidden: Hotlinking not allowed");
            return;
        }

        // validate Token
        if (!TokenValidator.validateToken(httpRequest, httpResponse)) {
            return;
        }

        // validate Timestamp
        if (!TimeValidator.validateTimestamp(httpRequest, httpResponse)) {
            return;
        }

        chain.doFilter(request, response);
    }
}

3. Token 验证工具

package com.et.filter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class TokenValidator {

    public static boolean validateToken(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String token = request.getParameter("token");
        String validToken = "your-predefined-token"; //set your predefined token here

        if (token == null || !token.equals(validToken)) {
            response.getWriter().write("403 Forbidden: Invalid Token");
            return false;
        }

        return true;
    }
}

4. 时间限制验证工具

package com.et.filter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.Instant;

public class TimeValidator {

    private static final long ALLOWED_TIME_DIFF = 300; // offset in seconds( 300 seconds)

    public static boolean validateTimestamp(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String timestampStr = request.getParameter("timestamp");

        if (timestampStr == null) {
            response.getWriter().write("403 Forbidden: Missing Timestamp");
            return false;
        }

        try {
            long timestamp = Long.parseLong(timestampStr);
            long currentTimestamp = Instant.now().getEpochSecond();

            if (Math.abs(currentTimestamp - timestamp) > ALLOWED_TIME_DIFF) {
                response.getWriter().write("403 Forbidden: Timestamp Expired");
                return false;
            }
        } catch (NumberFormatException e) {
            response.getWriter().write("403 Forbidden: Invalid Timestamp");
            return false;
        }

        return true;
    }
}

5. 静态资源示例

将一个图片文件711815.jpeg 放入 src/main/resources/static/images 文件夹中。

以上只是一些关键代码。

五、测试方式

  • 启动 Spring Boot 项目。

  • 测试访问图片资源:

curl -X GET "http://localhost:8088/static/example.jpg?token=your-predefined-token&timestamp=$(date +%s)" -H "Referer: http://localhost:8088"
  • 检查以下情况:

    • 如果 Referer 不正确,返回 403 Forbidden: Hotlinking not allowed
    • 如果 Token 无效,返回 403 Forbidden: Invalid Token
    • 如果时间戳超时,返回 403 Forbidden: Timestamp Expired

通过本文,您可以了解如何通过 Referer 校验、Token 验证和时间限制实现资源防盗链保护。如果有其他问题或需求,欢迎进一步探讨!

到此这篇关于基于SpringBoot实现防盗链功能的文章就介绍到这了,更多相关SpringBoot防盗链内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot使用JUL实现日志记录功能

    SpringBoot使用JUL实现日志记录功能

    在SpringBoot中,我们可以使用多种日志框架进行日志记录,其中,JUL(Java Util Logging)是Java平台自带的日志框架,它提供了简单的 API 和配置,可以轻松地进行日志记录,本文将介绍如何在 SpringBoot中使用JUL进行日志记录,并提供示例代码
    2023-06-06
  • Java8中Optional类型和Kotlin中可空类型的使用对比

    Java8中Optional类型和Kotlin中可空类型的使用对比

    这篇文章主要给大家介绍了关于Java8中Optional类型和Kotlin中可空类型的使用对比,文中通过示例代码给大家介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2017-09-09
  • JAVA中的日期时间类用法总结

    JAVA中的日期时间类用法总结

    这篇文章主要给大家介绍了关于JAVA中日期时间类用法的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • 深入理解Java 线程通信

    深入理解Java 线程通信

    这篇文章主要介绍了Java 线程通信的的相关资料,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-06-06
  • Java 是如何读取和写入浏览器Cookies的实例详解

    Java 是如何读取和写入浏览器Cookies的实例详解

    这篇文章主要介绍了Java 是如何读取和写入浏览器Cookies的实例的相关资料,需要的朋友可以参考下
    2016-09-09
  • 如何查看JVM使用的默认的垃圾收集器

    如何查看JVM使用的默认的垃圾收集器

    这篇文章主要介绍了如何查看JVM使用的默认的垃圾收集器,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • 关于Hadoop的HDFS集群

    关于Hadoop的HDFS集群

    这篇文章主要介绍了关于Hadoop的HDFS集群,Hadoop 如何配置集群、不同的计算机里又应该有怎样的配置,这些问题是在学习中产生的。本章的配置中将会提供一个典型的示例,需要的朋友可以参考下
    2023-05-05
  • Lombok基本注解之@SneakyThrows的作用

    Lombok基本注解之@SneakyThrows的作用

    @SneakyThrows注解是由lombok为咱们封装的,它能够为咱们的代码生成一个try...catch块,并把异常向上抛出来,下面这篇文章主要给大家介绍了关于Lombok基本注解之@SneakyThrows作用的相关资料,需要的朋友可以参考下
    2022-01-01
  • java集合迭代器Iterator中的remove陷阱

    java集合迭代器Iterator中的remove陷阱

    这篇文章主要介绍了java集合迭代器Iterator中的remove陷阱,需要的朋友可以参考下
    2016-04-04
  • Java中类赋值的解释实例详解

    Java中类赋值的解释实例详解

    这篇文章主要介绍了Java中类赋值的解释实例详解的相关资料,需要的朋友可以参考下
    2017-06-06

最新评论