Spring Boot 实现防盗链

news2025/4/20 11:57:26

在 Spring Boot 项目中实现防盗链可以通过多种方式,下面为你介绍两种常见的实现方法,分别是基于请求头 Referer 和基于令牌(Token)的防盗链。

基于请求头 Referer 的防盗链

这种方法通过检查请求头中的 Referer 字段,判断请求是否来自合法的来源。如果不是,则拒绝该请求。
以下是实现步骤和示例代码:

  1. 创建一个过滤器:用于拦截请求并检查 Referer 字段。
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.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

public class AntiLeachingFilter implements Filter {

    private List<String> allowedReferers;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        String refererConfig = filterConfig.getInitParameter("allowedReferers");
        if (Objects.nonNull(refererConfig)) {
            allowedReferers = Arrays.asList(refererConfig.split(","));
        }
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;

        String referer = httpServletRequest.getHeader("Referer");
        boolean isAllowed = false;

        if (Objects.isNull(referer)) {
            isAllowed = false;
        } else {
            for (String allowedReferer : allowedReferers) {
                if (referer.contains(allowedReferer)) {
                    isAllowed = true;
                    break;
                }
            }
        }

        if (isAllowed) {
            filterChain.doFilter(httpServletRequest, httpServletResponse);
        } else {
            httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Access Denied");
        }
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}
  1. 配置过滤器:在 Spring Boot 中注册该过滤器。
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean<AntiLeachingFilter> filterRegistrationBean() {
        FilterRegistrationBean<AntiLeachingFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new AntiLeachingFilter());
        registration.addInitParameter("allowedReferers", "127.0.0.1");
        registration.addUrlPatterns("/*");
        return registration;
    }

}

基于令牌(Token)的防盗链

此方法为每个请求生成一个唯一的令牌,并在请求时验证令牌的有效性。
以下是实现步骤和示例代码:

  1. 创建令牌生成和验证工具类:
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;

public class TokenGeneratorUtils {

    private static final String SECRET_KEY = "4t3t35y546yertdgsr3w4";

    /**
     * 生成用于防盗链的令牌(Token)。
     * 该方法通过将资源路径、过期时间和密钥拼接后进行 SHA-256 哈希计算,
     * 最终将计算得到的哈希值转换为十六进制字符串作为令牌返回。
     *
     * @param resourcePath  请求的资源路径,用于标识具体要访问的资源
     * @param expirationTime 令牌的过期时间,以毫秒为单位
     * @return 生成的令牌,是一个十六进制字符串
     */
    public static String generateToken(String resourcePath, long expirationTime) {
        String date = resourcePath + expirationTime + SECRET_KEY;
        try {
            // 借助 MessageDigest.getInstance("SHA-256") 方法获取一个 MessageDigest 实例,
            // 该实例使用的哈希算法为 SHA-256。SHA-256 属于安全哈希算法,能够将任意长度的输入数据转换为固定长度(256 位)的哈希值。
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            //调用 digest 方法对拼接后的字符串 data 进行哈希计算,返回一个字节数组 hash,此数组就是 data 的 SHA-256 哈希值。
            byte[] hash = digest.digest(date.getBytes());

            StringBuilder hexString = new StringBuilder();
            for (byte b : hash) {
                //字节转换为对应的十六进制字符串。
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) {//转换后的十六进制字符串长度为 1,在前面补一个 0,以保证每个字节都用两位十六进制数表示。
                    hexString.append('0');
                }
                //转换后的十六进制字符串追加到 hexString 中。
                hexString.append(hex);
            }
            return hexString.toString();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }

    public static boolean verifyToken(String resourcePath, String token, long expirationTime) {
        if (new Date().getTime() > expirationTime) {
            return false;
        }
        String generatedToken = generateToken(resourcePath, expirationTime);
        return generatedToken.equals(token);
    }

}
  1. 创建控制器处理请求并验证
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;

@RestController
@Slf4j
public class TestController {

    /**
     * curl --location '127.0.0.1:2223/test' \
     * --header 'Referer: 127.0.0.1'
     *
     * header头不传合法的Referer 127.0.0.1则拒绝访问
     * @return
     */
    @RequestMapping("/test")
    public String test() {
        return "ok";
    }

    @GetMapping("/protectedResource")
    public ResponseEntity<String> getProtectedResource(@RequestParam String token, @RequestParam long expirationTime) {
        String resourcePath = "/protectedResource";
        if (TokenGeneratorUtils.verifyToken(resourcePath, token, expirationTime)) {
            return ResponseEntity.ok("Access granted");
        } else {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).body("Invalid token");
        }
    }

    public static void main(String[] args) {
        // 资源路径
        String resourcePath = "/protectedResource";
        // 设置令牌过期时间,这里设置为当前时间往后 1 小时
        long expirationTime = new Date().getTime() + 3600 * 1000;
        // 生成令牌
        String token = TokenGeneratorUtils.generateToken(resourcePath, expirationTime);
        System.out.println(token);
        System.out.println(expirationTime);

    }
}

总结

  • 基于请求头 Referer 的防盗链:实现简单,但 Referer 字段容易被伪造。
  • 基于令牌(Token)的防盗链:安全性较高,但实现相对复杂,需要处理令牌的生成和验证逻辑。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2338706.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java 动态代理实现

Java 动态代理实现 一、JDK动态代理二、CGLIB动态代理三、动态代理的应用场景四、JDK代理与CGLIB代理比较 动态代理是Java中一种强大的技术&#xff0c;它允许在运行时创建代理对象&#xff0c;用于拦截对目标对象的方法调用。 一、JDK动态代理 JDK动态代理是Java标准库提供的代…

人脸扫描黑科技:多相机人脸扫描设备,打造你的专属数字分身

随着科技的迅猛发展&#xff0c;人脸扫描这个词已经并不陌生&#xff0c;通过人脸扫描设备制作超写实人脸可以为影视制作打造逼真角色、提升游戏沉浸感&#xff0c;还能助力教育机构等领域生产数字人以丰富教学资源&#xff0c;还在安防、身份识别等领域发挥关键作用&#xff0…

基于Python的中国象棋小游戏的设计与实现

基于Python的中国象棋小游戏的设计与实现 第一章 绪论1.1 研究背景1.2 研究意义 第二章 需求分析2.1 需求分析2.1.1核心功能需求2.1.2 用户体验需求2.1.3 衍生功能需求 2.2 可行性分析2.2.1 技术可行性2.2.2 经济可行性2.2.3 市场可行性2.2.4 法律与合规性 第三章 概要设计3.1 …

简单好用的在线工具

用AI写了一些在线工具&#xff0c;简介好用&#xff0c;推荐给大家&#xff0c;欢迎大家使用并提议意见。 网址&#xff1a;https://www.bittygarden.com/ 目前已有以下功能&#xff1a; MD5SM3SHAUnicode 编码Unicode 解码Base32 编码Base32 解码Base64 编码Base64 解码URL …

外卖市场规模巨大,是宽广赛道?京东CEO发言

大家好&#xff0c;我是小悟。 在竞争激烈的外卖市场中&#xff0c;京东作为新入局者&#xff0c;正以独特的战略视角和坚定的决心&#xff0c;重新定义外卖行业的竞争格局。 近日&#xff0c;京东集团CEO许冉在接受采访时表示&#xff1a;“外卖行业本就是一个宽广的赛道&am…

Flutter PIP 插件 ---- iOS Video Call 自定义PIP WINDOW渲染内容

简介 画中画(Picture in Picture, PiP)是一项允许用户在使用其他应用时继续观看视频内容的功能。本文将详细介绍如何在 iOS 应用中实现 PiP 功能&#xff0c;包括自定义内容渲染和控制系统控件的显示。 效果展示 功能特性 已完成功能 ✅ 基础 PiP 接口实现&#xff08;设置…

xml+html 概述

1.什么是xml xml 是可扩展标记语言的缩写&#xff1a; Extensible Markup Language。 <root><h1> text 1</h1> </root> web 应用开发&#xff0c;需要配置 web.xml&#xff0c;就是个典型的 xml文件 <web-app><servlet><servlet-name&…

Java从入门到“放弃”(精通)之旅——数组的定义与使用⑥

Java从入门到“放弃”&#xff08;精通&#xff09;之旅&#x1f680;——数组⑥ 前言——什么是数组&#xff1f; 数组&#xff1a;可以看成是相同类型元素的一个集合&#xff0c;在内存中是一段连续的空间。比如现实中的车库&#xff0c;在java中&#xff0c;包含6个整形类…

如何对docker镜像存在的gosu安全漏洞进行修复——筑梦之路

这里以mysql的官方镜像为例进行说明&#xff0c;主要流程为&#xff1a; 1. 分析镜像存在的安全漏洞具体是什么 2. 根据分析结果有针对性地进行修复处理 3. 基于当前镜像进行修复安全漏洞并复核验证 # 镜像地址mysql:8.0.42 安全漏洞现状分析 dockerhub网站上获取该镜像的…

基于springboot的老年医疗保健系统

博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;熟悉各种主流语言&#xff0c;精通java、python、php、爬虫、web开发&#xff0c;已经做了六年的毕业设计程序开发&#xff0c;开发过上千套毕业设计程序&#xff0c;没有什么华丽的语言&#xff0…

使用Ollama本地运行deepseek模型

Ollama 是一个用于管理 AI 模型的工具 下载 Ollama Ollama 选择版本 下载模型 安装好后&#xff0c;下载模型 选择模型 选择模型大小&#xff0c;复制对应命令&#xff08;越大越聪明&#xff0c;但是内存要求越高&#xff09; 打开控制台运行命令&#xff0c;第一次运行会自动…

网络编程 - 3

目录 UDP 连接拓展&#xff08;业务逻辑&#xff09; 词典服务器实现 完 UDP 连接拓展&#xff08;业务逻辑&#xff09; 我们上一篇文章实现了一个回显服务器&#xff0c;在服务端中业务方法 process 中&#xff0c;只是单纯的将客户端输入的东西 return 了一下&#xff0…

5G 毫米波滤波器的最优选择是什么?

新的选择有很多&#xff0c;但到目前为止还没有明确的赢家。 蜂窝电话技术利用大量的带带&#xff0c;为移动用途提供不断增加的带宽。 其中的每一个频带都需要透过滤波器将信号与其他频带分开&#xff0c;但目前用于手机的滤波器技术可能无法扩展到5G所规划的全部毫米波&#…

【HDFS入门】HDFS性能调优实战:压缩与编码技术深度解析

目录 1 HDFS性能调优概述 2 HDFS压缩技术原理与应用 2.1 常见压缩算法比较 2.2 压缩流程架构 2.3 压缩配置实践 3 列式存储编码技术 3.1 ORC与Parquet对比 3.2 ORC文件结构 3.3 Parquet编码流程 4 性能调优实战建议 4.1 压缩选择策略 4.2 编码优化技巧 5 性能测试…

如何在 IntelliJ IDEA 中安装通义灵码 - AI编程助手提升开发效率

随着人工智能技术的飞速发展&#xff0c;AI 编程助手已成为提升开发效率和代码质量的强大工具。在众多 AI 编程助手之中&#xff0c;阿里云推出的通义灵码凭借其智能代码补全、代码解释、生成单元测试等丰富功能&#xff0c;脱颖而出&#xff0c;为开发者带来了全新的编程体验。…

从零到一:管理系统设计新手如何快速上手?

管理系统设计是一项复杂而富有挑战性的任务&#xff0c;它要求设计者具备多方面的知识和技能&#xff0c;包括需求分析、架构设计、数据管理、用户界面设计等。对于初次接触这一领域的新手而言&#xff0c;如何快速上手并成为一名合格的管理系统设计者呢&#xff1f;本文将从管…

WSL (ext4.vhdx文件)占用空间过大,清理方式记录,同时更改 WSL 保存位置

一、问题 之前使用 WSL Ubuntu 进行过开发板的 Yocto 项目编译&#xff0c;占用空间达到了 70GB 多的空间。后来进行了项目迁移&#xff0c;删除了 WSL 中的所有文件&#xff0c;但是从 Windows 查看空间占用却没有减少&#xff1a; 占用依然是 70 多&#xff0c;查阅发现 vhdx…

《软件设计师》复习笔记(14.2)——统一建模语言UML、事务关系图

目录 1. UML概述 2. UML构造块 (1) 事物&#xff08;Things&#xff09; (2) 关系&#xff08;Relationships&#xff09; 真题示例&#xff1a; 3. UML图分类 (1) 结构图&#xff08;静态&#xff09; (2) 行为图&#xff08;动态&#xff09; 4. 核心UML图详解 5.…

[文献阅读] EnCodec - High Fidelity Neural Audio Compression

[文献信息]&#xff1a;[2210.13438] High Fidelity Neural Audio Compression facebook团队提出的一个用于高质量音频高效压缩的模型&#xff0c;称为EnCodec。Encodec是VALL-E的重要前置工作&#xff0c;正是Encodec的压缩量化使得VALL-E能够出现&#xff0c;把语音领域带向大…

【操作系统原理01】操作系统引论

文章目录 大纲一、中断与异常0.大纲1. 中断的作用2. 中断类型2.1 内中断2.2 外中断2.3 判断内外中断 3. 中断机制原理 二、系统调用0. 大纲1.什么是系统调用2.系统调用分类 三、操作性系统内核(了解)0.大纲1.内核2.各种操作系统结构特性 四、操作系统引论0.大纲1.磁盘存储 图片…