Title

fastDFS+SpringBoot实现文件防盗链

FastDFS内置防盗链采用Token的方式。Token是带时效的,也就是说在设定的时间范围内,比如1分钟,token是有效的。token包含了文件id、时间戳ts和密钥。
FastDFS在URL中带上当前时间戳和带时效的token,参数名分别为ts和token。Token的生成和校验都是在服务端,因此不会存在安全问题。

例如:

http://你的IP/meng/M00/00/00/rBFE2VwohBOAOrnIAABDRU16ivg948.png?token=f48b02095128da73e43006d2b53f0001&ts=1546159147

配置文件说明

1、http.conf中防盗链相关的几个参数如下:

# cd /etc/fdfs
# vim /etc/fdfs/http.conf
# if use token to anti-steal
# default value is false (0)   
# 是否做token检查,缺省值为false。
http.anti_steal.check_token=true
 
# token TTL (time to live), seconds
# default value is 600
# TTL,即生成token的有效时长(秒)
http.anti_steal.token_ttl=120
 
# secret key to generate anti-steal token
# this parameter must be set when http.anti_steal.check_token set to true
# the length of the secret key should not exceed 128 bytes
# 生成token的密钥,尽量设置得长一些,千万不要泄露出去
http.anti_steal.secret_key=FastDFS1234567890
 
# return the content of the file when check token fail
# default value is empty (no file sepecified)
# 检查失败,返回的文件内容,需指定本地文件名
http.anti_steal.token_check_fail=/home/fileError.png

需重启 tracker、storage 和 nginx

# fdfs_trackerd /etc/fdfs/tracker.conf
# fdfs_trackerd /etc/fdfs/tracker.conf restart
waiting for pid [23891] exit ...
starting ...
# fdfs_storaged /etc/fdfs/storage.conf
# fdfs_trackerd /etc/fdfs/tracker.conf restart
waiting for pid [26848] exit ...
starting ...
# ./nginx -s reload
ngx_http_fastdfs_set pid=26832

2、application-dev.properties

# fastDFS 
fdfs.so-timeout=1501
fdfs.connect-timeout=601
fdfs.thumb-image.width=150
fdfs.thumb-image.height=150
fdfs.web-server-url=你的IP/
fdfs.tracker-list[0]=你的IP:22122
fdfs.http.anti_steal_token = true
fdfs.http.secret_key = FastDFS1234567890

项目中增加依赖

<!-- fastDFS -->
<dependency>
    	<groupId>com.github.tobato</groupId>
    	<artifactId>fastdfs-client</artifactId>
   	<version>1.26.2</version>
</dependency>
<dependency>
	<groupId>net.oschina.zcx7878</groupId>
	<artifactId>fastdfs-client-java</artifactId>
	<version>1.27.0.0</version>
</dependency>

引入fastDFS配置

import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableMBeanExport;
import org.springframework.context.annotation.Import;
import org.springframework.jmx.support.RegistrationPolicy;
 
import com.github.tobato.fastdfs.FdfsClientConfig;
 
@Configuration
@Import(FdfsClientConfig.class)
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)// 解决jmx重复注册bean的问题
public class ComponetImport {
    // 导入依赖组件
}

工具类

import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
 
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;
import org.springframework.web.multipart.MultipartFile;
 
import com.github.tobato.fastdfs.conn.FdfsWebServer;
import com.github.tobato.fastdfs.domain.StorePath;
import com.github.tobato.fastdfs.exception.FdfsUnsupportStorePathException;
import com.github.tobato.fastdfs.proto.storage.DownloadByteArray;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
 
 
@Component
public class FastDFSClient {
 
    @Autowired
    private FastFileStorageClient storageClient;
 
    @Autowired
    private FdfsWebServer fdfsWebServer;
 
    /**
     * 上传文件
     * @param file 文件对象
     * @return 文件访问地址
     * @throws IOException
     */
    public String uploadFile(MultipartFile file) throws IOException {
        StorePath storePath = storageClient.uploadFile(file.getInputStream(),file.getSize(), FilenameUtils.getExtension(file.getOriginalFilename()),null);
        return getResAccessUrl(storePath);
    }
 
    /**
     * 上传文件
     * @param file 文件对象
     * @return 文件访问地址
     * @throws IOException
     */
    public String uploadFile(File file) throws IOException {
        FileInputStream inputStream = new FileInputStream (file);
        StorePath storePath = storageClient.uploadFile(inputStream,file.length(), FilenameUtils.getExtension(file.getName()),null);
        return getResAccessUrl(storePath);
    }
 
    /**
     * 将一段字符串生成一个文件上传
     * @param content 文件内容
     * @param fileExtension
     * @return
     */
    public String uploadFile(String content, String fileExtension) {
        byte[] buff = content.getBytes(Charset.forName("UTF-8"));
        ByteArrayInputStream stream = new ByteArrayInputStream(buff);
        StorePath storePath = storageClient.uploadFile(stream,buff.length, fileExtension,null);
        return getResAccessUrl(storePath);
    }
 
    // 封装图片完整URL地址
    private String getResAccessUrl(StorePath storePath) {
        String fileUrl = fdfsWebServer.getWebServerUrl() + storePath.getFullPath();
        return fileUrl;
    }
    
    /**
     * 下载文件
     * @param fileUrl 文件url
     * @return
     */
    public byte[]  download(String fileUrl) {
    	 String group = fileUrl.substring(0, fileUrl.indexOf("/"));
         String path = fileUrl.substring(fileUrl.indexOf("/") + 1);
         byte[] bytes = storageClient.downloadFile(group, path, new DownloadByteArray());
         return bytes;
    }
 
    /**
     * 删除文件
     * @param fileUrl 文件访问地址
     * @return
     */
    public void deleteFile(String fileUrl) {
        if (StringUtils.isEmpty(fileUrl)) {
            return;
        }
        try {
            StorePath storePath = StorePath.praseFromUrl(fileUrl);
            storageClient.deleteFile(storePath.getGroup(), storePath.getPath());
        } catch (FdfsUnsupportStorePathException e) {
            e.getMessage();
        }
    }
 
}

文件的上传、下载 与 访问获取的 token

import org.apache.commons.io.IOUtils;
import org.csource.common.MyException;
import org.csource.fastdfs.ProtoCommon;
import org.meng.project.common.FileUtil;
import org.meng.project.entity.Filesource;
import org.meng.project.service.ExcelService;
import org.meng.project.service.FileService;
import org.meng.project.util.FastDFSClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
 
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.*;
 
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
@Controller
@RequestMapping("/fdfs")
public class FastDFSController {
	
	@Autowired
	private FastDFSClient fdfsClient;
	
	@Value("${fdfs.web-server-url}")
    private String fastdfsUrl;
	
	@Value("${fdfs.http.secret_key}")
    private String fastdfsToken;
 
	/**
	 * 文件上传
	 * @param file
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("/upload/file")
	@ResponseBody
	public Map<String,Object> upload(@RequestParam("file") MultipartFile file, Model model) throws Exception{
		Map<String,Object> resultMap = new HashMap<>();
		String url = null;
		
		try {
			url = fdfsClient.uploadFile(file);
			resultMap.put("code", 200);
			resultMap.put("message", "上传成功");
			resultMap.put("url", url);
			System.out.println(url);
        } catch (Exception e) {
       	    // TODO: handle exception
        	resultMap.put("status", 500);
        	resultMap.put("message", "上传异常!");
        }
		
		return resultMap;
	}
	
	/**
	 * 文件下载
	 * @param fileUrl  url 开头从组名开始
	 * @param response
	 * @throws Exception
	 */
	@RequestMapping(value="/download", method = {RequestMethod.GET})
	public void  download(HttpServletResponse response, HttpServletRequest request) throws Exception{
		String fileUrl = request.getParameter("fileUrl");
		
		byte[] data = fdfsClient.download(fileUrl);
		
		response.setCharacterEncoding("UTF-8");
		response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode("test.jpg", "UTF-8"));
        
		// 写出
		ServletOutputStream outputStream = response.getOutputStream();
		IOUtils.write(data, outputStream);
	}
	
	/**
	 * 生成访问链接
	 */
	@RequestMapping(value="/location", method = {RequestMethod.GET})
	public String location(HttpServletResponse response, HttpServletRequest request, Model model) {
		String fileUrl = request.getParameter("location");
		System.out.println(fileUrl);
		//token
    	String token = fastdfsToken;
    	String IP = fastdfsUrl;
    	
		fileUrl = getToken(fileUrl,token,IP);
		
		model.addAttribute("Url", fileUrl);
		
		return "tools/uploadfile";
	}
	
    /**
    * 获取访问服务器的token,拼接到地址后面
    *
    * @param fid 文件路径 group1/M00/00/00/wKgzgFnkTPyAIAUGAAEoRmXZPp876.jpeg
    * @param secret_key 密钥
    * @return 返回token,如: token=078d370098b03e9020b82c829c205e1f&ts=1508141521
    */
   public static String getToken(String fid, String secret_key, String IP){
	
	   String substring = fid.substring(fid.indexOf("/")+1);
	   //unix时间戳 以秒为单位
	   int ts = (int) (System.currentTimeMillis() / 1000);
	   String token=new String();
	   try {
	   	token= ProtoCommon.getToken(substring, ts, secret_key);
	   } catch (UnsupportedEncodingException e) {
		   e.printStackTrace();
	   } catch (NoSuchAlgorithmException e) {
		   e.printStackTrace();
	   } catch (MyException e) {
		   e.printStackTrace();
		}
	   StringBuilder sb = new StringBuilder();
	   sb.append(IP);
	   sb.append(fid);
	   sb.append("?token=").append(token);
	   sb.append("&ts=").append(ts);
	   //System.out.println(sb.toString());
	   
       return sb.toString();
   }
}

效果

1、上传

2、下载

3、获取访问链接:

访问效果图:


原文章地址:
https://blog.csdn.net/W_Meng_H/article/details/85402879

posted @ 2024-06-14 14:52  快乐小洋人  阅读(60)  评论(0编辑  收藏  举报