SpringBoot集成FastDFS+Nginx整合基于Token的防盗链的方法

yizhihongxing

下面是 SpringBoot 集成 FastDFS+Nginx 整合基于 Token 的防盗链的方法的完整攻略:

简介

FastDFS 是一个开源的分布式文件系统,由阿里巴巴的余庆编写,目前由开源社区进行开发,FastDFS 是基于 Linux 的文件系统,实现了一个简单的文件系统,它是以 Tracker Server 和 Storage Server 为两个服务端来运行的。Nginx 是目前非常流行的 Web 服务器软件,在线服务商也广泛采用 Nginx 作为服务端的软件之一。在使用 FastDFS 存储文件的时候,我们通常需要使用 Nginx 对文件进行访问,而防盗链可以有效的保护用户文件的安全性,防止 URL 被泄露并在未授权的情况下访问。

整合过程

  1. 添加 FastDFS 依赖

在 pom.xml 中添加 FastDFS 的依赖,这里我们使用的版本为1.27。

<dependency>
  <groupId>com.github.tobato</groupId>
  <artifactId>fastdfs-client</artifactId>
  <version>1.27.2</version>
</dependency>
  1. 配置 FastDFS 客户端

创建 FastDFS 客户端的配置类 FastDFSClientConfig,用于配置 FastDFS 链接信息和客户端工厂对象 FastDFS 基于 Tracker 的客户端。

@Configuration
public class FastDFSClientConfig {

    /**
     * Default FastDFS properties
     */
    @Value("${fastdfs.tracker-list}")
    private String trackerList;

    @Bean
    public DefaultFastFileStorageClient storageClient() {
        return new DefaultFastFileStorageClient(trackerClient());
    }

    @Bean
    public TrackerClient trackerClient() {
        return new DefaultTrackerClient();
    }

    @Bean
    public ConnectionPoolConfig connectionPoolConfig() {
        ConnectionPoolConfig connectionPoolConfig = new ConnectionPoolConfig();
        connectionPoolConfig.setMinPoolSize(1);
        connectionPoolConfig.setMaxPoolSize(10);
        connectionPoolConfig.setMaxIdleTime(3600);
        return connectionPoolConfig;
    }

    @Bean(initMethod = "init")
    public FastFileStorageClientFactory storageClientFactory() {
        FastFileStorageClientFactory factory = new FastFileStorageClientFactory();
        factory.setConnectionPoolConfig(connectionPoolConfig());
        factory.setStorageClient(storageClient());
        factory.setTrackerClient(trackerClient());
        return factory;
    }
}
  1. 配置 Nginx

在 Nginx 中配置 FastDFS 模块和防盗链模块,Nginx 需要定时更新防盗链 Token 配置,以保证访问安全性。

# nginx-fastdfs.conf

worker_processes auto;
events {
    worker_connections 1024;
}

http {
    default_type       application/octet-stream;
    sendfile            on;
    # gzip              on;
    server {
        listen       80;
        server_name  localhost;
        access_log   logs/access.log  access;
        location ~ /group([0-9]+)/M00/(.*)$ {
            alias /data/fastdfs/storage/data/data/$1/$2;
        }

        location /group1/M00/ {
            ngx_fastdfs_module;
            ngx_fastdfs_tracker $tracker_server;
            ngx_fastdfs_store_path /data/fastdfs/storage/data;
        }

        location / {
            root   html;
            add_header 'Access-Control-Allow-Origin' '*';
        }

        location /download {
            external;
            internal;
            add_header Content-Disposition "attachment;filename=$arg_filename;";
        }

        # token
        location /upload {
            add_header Access-Control-Allow-Origin *;
            add_header Access-Control-Allow-Headers Origin, X-Requested-With, Content-Type, Accept;
            internal;
            set $token_hash "";
            if ($http_secret_key) {
                set $token_hash $http_secret_key;
            }
            set $s $query_string;
            if ($args) {
                set $s "${s}&";
            }
            set $s "${s}token_hash=${token_hash}";
            set_md5 $token $s;
            set $arg_token $token;
        }
    }
}
  1. 集成 Token 配置

创建 Token 的验证工具类 TokenUtils,用于生成和验证 Token。

@Component
public class TokenUtils {

    /**
     * 密钥
     */
    private static final String SECRET_KEY = "MY_SECRET_KEY";

    /**
     * 生成 Token
     *
     * @param path
     * @return
     */
    public static String generateToken(String path) {
        Long timestamp = System.currentTimeMillis() / 1000L;
        String tokenMeta = path + "&" + SECRET_KEY + "&" + timestamp.toString();
        String token = DigestUtils.md5Hex(tokenMeta);
        return token + "&" + timestamp;
    }

    /**
     * 验证 Token
     *
     * @param path
     * @param token
     * @return
     */
    public static boolean verifyToken(String path, String token) {
        String[] tokenArr = token.split("&");
        if (tokenArr.length != 2) {
            return false;
        }
        String signToken = tokenArr[0];
        Long timestamp = Long.valueOf(tokenArr[1]);
        Long currentTimestamp = System.currentTimeMillis() / 1000L;
        if (currentTimestamp - timestamp > 60 * 60) {
            return false;
        }
        String tokenMeta = path + "&" + SECRET_KEY + "&" + timestamp.toString();
        String calToken = DigestUtils.md5Hex(tokenMeta);
        if (StringUtils.equals(signToken, calToken)) {
            return true;
        } else {
            return false;
        }
    }
}
  1. 编写防盗链拦截器

创建文件防盗链拦截器 DownloadTokenInterceptor,用于拦截文件下载的请求,验证 Token 的有效性和访问权限。

@Component
public class DownloadTokenInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        // 是否有 Secret Key
        if (StringUtils.isBlank(request.getHeader("Secret-Key"))) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }

        // 获取 Token,格式为:ts&token
        String token = request.getHeader("Token");

        // 验证 Token
        if (!TokenUtils.verifyToken(request.getRequestURI(), token)) {
            response.sendError(HttpServletResponse.SC_FORBIDDEN, "Token is invalid");
            return false;
        }

        return true;
    }
}
  1. 使用 TokenInterceptor 拦截器

在 SpringBoot 应用中注册 DownloadTokenInterceptor 拦截器,并将拦截器加在需要拦截的路径下。

@Configuration
public class ConfigurerAdapter extends WebMvcConfigurerAdapter {

    @Autowired
    private DownloadTokenInterceptor downloadTokenInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(downloadTokenInterceptor).addPathPatterns("/download/**");
        super.addInterceptors(registry);
    }
}

至此,SpringBoot 集成 FastDFS+Nginx 整合基于 Token 的防盗链的方法已经完成。

示例

示例1:文件上传

  1. 前端页面示例:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>文件上传测试</title>
</head>
<body>
  <form action="http://localhost:8080/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="file" />
    <button type="submit">Submit</button>
  </form>
</body>
</html>
  1. 文件上传控制器示例:
@Controller
public class FileUploadController {

    @PostMapping("/upload")
    public String upload(@RequestParam("file") MultipartFile file) throws IOException {
        String groupName = "group1";
        String filepath = "test.jpg";
        StorePath storePath = storageClientFactory.getStorageClient().uploadFile(groupName, file.getInputStream(), file.getSize(), FilenameUtils.getExtension(file.getOriginalFilename()));
        return storePath.getFullPath();
    }
}

示例2:文件下载

  1. 前端页面示例:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>文件下载测试</title>
</head>
<body>
  <form action="http://localhost:8080/download" method="post">
    <input type="hidden" name="filename" value="test.jpg" />
    <input type="hidden" name="token_hash" value="123" />
    <button type="submit">Submit</button>
  </form>
</body>
</html>
  1. 文件下载控制器示例:
@Controller
public class FileDownloadController {

    @PostMapping("/download")
    public void download(String filename, String token_hash, HttpServletResponse response) throws Exception {
        OutputStream out = null;
        InputStream in = null;
        response.setHeader("Content-disposition", "attachment;filename=" + filename);
        response.setContentType("application/octet-stream");
        String token = token_hash + "&" + TokenUtils.generateToken(filename);
        String url = "http://localhost/group1/M00/00/00/" + filename + "?" + "token=" + token;
        try {
            in = new URL(url).openStream();
            out = response.getOutputStream();
            byte[] buffer = new byte[2048];
            int len = 0;
            while ((len = in.read(buffer)) > 0) {
                out.write(buffer, 0, len);
            }
            out.flush();
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }
}

希望我的讲解能对你有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringBoot集成FastDFS+Nginx整合基于Token的防盗链的方法 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • layui+jquery支持IE8的表格分页方法

    下面为您详细讲解“layui+jquery支持IE8的表格分页方法”的完整攻略。 简介 Layui是一款轻量级的前端UI框架,兼容性良好,但官方仅支持IE10以上版本。有时候我们需要兼容低版本的IE浏览器,本文就是讲解使用layui+jquery实现支持IE8的表格分页方法。 准备工作 引入Layui和jquery库; 定义表格结构,设置表头等; 引入分页组…

    Java 2023年6月15日
    00
  • MyBatis-Ext快速入门实战

    MyBatis-Ext快速入门实战攻略 MyBatis-Ext是MyBatis的一个增强工具包,可以提供更加便捷的使用方式,提高开发效率。本文将提供一个MyBatis-Ext的快速入门实战攻略,包含配置、实现及示例演示。 配置 引入MyBatis-Ext的依赖 xml <dependency> <groupId>com.github.…

    Java 2023年5月20日
    00
  • Eclipse配置Tomcat和JDK步骤图解

    下面是Eclipse配置Tomcat和JDK的详细攻略: 步骤一:下载和安装JDK并设置环境变量 前往Oracle官网下载JDK安装包并安装; 新建系统环境变量JAVA_HOME,值为JDK的安装路径; 在系统环境变量中,找到Path,添加%JAVA_HOME%\bin路径。 步骤二:下载Tomcat并在Eclipse中安装 前往Tomcat官网下载最新版本…

    Java 2023年5月19日
    00
  • Java中的Graphics2D类基本使用教程

    接下来我将为你详细讲解Java中的Graphics2D类基本使用教程。Graphics2D类是Java图形库中比较重要的一个类,它可以用于绘制二维图形,包括直线、多边形、文字、图像等等。Graphics2D类是Graphics类的子类,它可以在Graphics基础上提供更丰富和更高级的图形绘制功能。 1. Graphics2D类的创建 要使用Graphics…

    Java 2023年5月26日
    00
  • 如何使用Java线程池?

    使用Java线程池可以提高并发处理的效率,避免过多的线程导致系统性能下降。下面是Java线程池的完整使用攻略。 什么是线程池? 在讲如何使用线程池之前,先来了解一下什么是线程池。线程池是一种管理和使用线程的机制,可以方便地重用已创建的线程,避免频繁地创建和销毁线程所带来的开销。线程池只有在需要创建线程时才创建新线程,当线程完成任务后,它并不会立即销毁线程,而…

    Java 2023年5月11日
    00
  • Java获取一维数组的最小值实现方法

    当需要获取一维数组中最小值时,Java提供了多种实现方法,本文将对这些方法进行详细讲解。 方法一:使用for循环进行遍历 此方法是最基本的实现方式,在遍历整个数组的过程中,用一个临时变量记录最小值,并不断更新该变量,最终得到整个数组中的最小值。 示例代码: public int getMinValue(int[] arr) { int min = arr[0…

    Java 2023年5月26日
    00
  • 解决JDBC的class.forName()问题

    解决 JDBC 的 Class.forName() 问题 在使用 JDBC 连接数据库时,我们通常使用的是以下代码: Class.forName("com.mysql.cj.jdbc.Driver"); Connection conn = DriverManager.getConnection(url, username, passwor…

    Java 2023年6月16日
    00
  • Java中的File类是什么?

    File类是Java中的一个类,用于操作文件或文件夹。它主要用于获取文件或文件夹的属性、操作(创建、删除、重命名等)文件或文件夹。 File类的基本使用 File类提供了多个构造方法,可以使用文件路径或URI来创建一个文件实例,例如: // 通过文件路径创建File实例 File file = new File("C:/test.txt"…

    Java 2023年4月27日
    00
合作推广
合作推广
分享本页
返回顶部