Browse Source

优化 file:// 协议访问授信目录的代码结构

chenkailing 2 years ago
parent
commit
82f6d3565f

+ 65 - 0
server/src/main/java/cn/keking/config/WebConfig.java

@@ -1,11 +1,17 @@
 package cn.keking.config;
 
+import cn.keking.web.filter.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
+import java.util.HashSet;
+import java.util.Set;
+
 /**
  * @author: chenjh
  * @since: 2019/4/16 20:04
@@ -23,4 +29,63 @@ public class WebConfig implements WebMvcConfigurer {
         LOGGER.info("Add resource locations: {}", filePath);
         registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/","classpath:/resources/","classpath:/static/","classpath:/public/","file:" + filePath);
     }
+
+    @Bean
+    public FilterRegistrationBean<ChinesePathFilter> getChinesePathFilter() {
+        ChinesePathFilter filter = new ChinesePathFilter();
+        FilterRegistrationBean<ChinesePathFilter> registrationBean = new FilterRegistrationBean<>();
+        registrationBean.setFilter(filter);
+        return registrationBean;
+    }
+
+    @Bean
+    public FilterRegistrationBean<TrustHostFilter> getTrustHostFilter() {
+        Set<String> filterUri = new HashSet<>();
+        filterUri.add("/onlinePreview");
+        filterUri.add("/picturesPreview");
+        TrustHostFilter filter = new TrustHostFilter();
+        FilterRegistrationBean<TrustHostFilter> registrationBean = new FilterRegistrationBean<>();
+        registrationBean.setFilter(filter);
+        registrationBean.setUrlPatterns(filterUri);
+        return registrationBean;
+    }
+
+    @Bean
+    public FilterRegistrationBean<TrustDirFilter> getTrustDirFilter() {
+        Set<String> filterUri = new HashSet<>();
+        filterUri.add("/onlinePreview");
+        filterUri.add("/picturesPreview");
+        filterUri.add("/getCorsFile");
+        TrustDirFilter filter = new TrustDirFilter();
+        FilterRegistrationBean<TrustDirFilter> registrationBean = new FilterRegistrationBean<>();
+        registrationBean.setFilter(filter);
+        registrationBean.setUrlPatterns(filterUri);
+        return registrationBean;
+    }
+
+    @Bean
+    public FilterRegistrationBean<BaseUrlFilter> getBaseUrlFilter() {
+        Set<String> filterUri = new HashSet<>();
+        filterUri.add("/index");
+        filterUri.add("/onlinePreview");
+        filterUri.add("/picturesPreview");
+        BaseUrlFilter filter = new BaseUrlFilter();
+        FilterRegistrationBean<BaseUrlFilter> registrationBean = new FilterRegistrationBean<>();
+        registrationBean.setFilter(filter);
+        registrationBean.setUrlPatterns(filterUri);
+        return registrationBean;
+    }
+
+    @Bean
+    public FilterRegistrationBean<AttributeSetFilter> getWatermarkConfigFilter() {
+        Set<String> filterUri = new HashSet<>();
+        filterUri.add("/index");
+        filterUri.add("/onlinePreview");
+        filterUri.add("/picturesPreview");
+        AttributeSetFilter filter = new AttributeSetFilter();
+        FilterRegistrationBean<AttributeSetFilter> registrationBean = new FilterRegistrationBean<>();
+        registrationBean.setFilter(filter);
+        registrationBean.setUrlPatterns(filterUri);
+        return registrationBean;
+    }
 }

+ 47 - 0
server/src/main/java/cn/keking/utils/WebUtils.java

@@ -1,11 +1,15 @@
 package cn.keking.utils;
 
 import io.mola.galimatias.GalimatiasParseException;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.util.Base64Utils;
 
+import javax.servlet.ServletRequest;
 import java.io.UnsupportedEncodingException;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -17,6 +21,7 @@ public class WebUtils {
 
     /**
      * 获取标准的URL
+     *
      * @param urlStr url
      * @return 标准的URL
      */
@@ -138,4 +143,46 @@ public class WebUtils {
         }
         return url.substring(0, fileNameStartIndex) + encodedFileName + url.substring(fileNameEndIndex);
     }
+
+    /**
+     * 从 ServletRequest 获取预览的源 url , 已 base64 解码
+     *
+     * @param request 请求 request
+     * @return url
+     */
+    public static String getSourceUrl(ServletRequest request) {
+        String url = request.getParameter("url");
+        String urls = request.getParameter("urls");
+        String currentUrl = request.getParameter("currentUrl");
+        String urlPath = request.getParameter("urlPath");
+        if (StringUtils.isNotBlank(url)) {
+            return new String(Base64Utils.decodeFromString(url), StandardCharsets.UTF_8);
+        }
+        if (StringUtils.isNotBlank(currentUrl)) {
+            return new String(Base64Utils.decodeFromString(currentUrl), StandardCharsets.UTF_8);
+        }
+        if (StringUtils.isNotBlank(urlPath)) {
+            return new String(Base64Utils.decodeFromString(urlPath), StandardCharsets.UTF_8);
+        }
+        if (StringUtils.isNotBlank(urls)) {
+            urls = new String(Base64Utils.decodeFromString(urls), StandardCharsets.UTF_8);
+            String[] images = urls.split("\\|");
+            return images[0];
+        }
+        return null;
+    }
+
+    /**
+     * 获取 url 的 host
+     * @param urlStr url
+     * @return host
+     */
+    public static String getHost(String urlStr) {
+        try {
+            URL url = new URL(urlStr);
+            return url.getHost().toLowerCase();
+        } catch (MalformedURLException ignored) {
+        }
+        return null;
+    }
 }

+ 4 - 41
server/src/main/java/cn/keking/web/controller/OnlinePreviewController.java

@@ -1,19 +1,16 @@
 package cn.keking.web.controller;
 
-import cn.keking.config.ConfigConstants;
 import cn.keking.model.FileAttribute;
+import cn.keking.service.FileHandlerService;
 import cn.keking.service.FilePreview;
 import cn.keking.service.FilePreviewFactory;
-
 import cn.keking.service.cache.CacheService;
 import cn.keking.service.impl.OtherFilePreviewImpl;
-import cn.keking.service.FileHandlerService;
 import cn.keking.utils.WebUtils;
 import fr.opensagres.xdocreport.core.io.IOUtils;
 import io.mola.galimatias.GalimatiasParseException;
 import jodd.io.NetUtil;
 import org.apache.commons.codec.binary.Base64;
-import org.artofsolving.jodconverter.util.PlatformUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Controller;
@@ -25,13 +22,12 @@ import org.springframework.web.bind.annotation.ResponseBody;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import java.io.*;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
 import java.net.URL;
-import java.net.URLDecoder;
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.List;
-import java.util.Locale;
 
 import static cn.keking.service.FilePreview.PICTURE_FILE_PREVIEW_PAGE;
 
@@ -65,9 +61,6 @@ public class OnlinePreviewController {
             String errorMsg = String.format(BASE64_DECODE_ERROR_MSG, "url");
             return otherFilePreview.notSupportedFile(model, errorMsg);
         }
-        if (!allowPreview(fileUrl)) {
-            return otherFilePreview.notSupportedFile(model, "该文件不允许预览:" + fileUrl);
-        }
         FileAttribute fileAttribute = fileHandlerService.getFileAttribute(fileUrl, req);
         model.addAttribute("file", fileAttribute);
         FilePreview filePreview = previewFactory.get(fileAttribute);
@@ -93,14 +86,8 @@ public class OnlinePreviewController {
         String currentUrl = req.getParameter("currentUrl");
         if (StringUtils.hasText(currentUrl)) {
             String decodedCurrentUrl = new String(Base64.decodeBase64(currentUrl));
-            if (!allowPreview(decodedCurrentUrl)) {
-                return otherFilePreview.notSupportedFile(model, "该文件不允许预览:" + decodedCurrentUrl);
-            }
             model.addAttribute("currentUrl", decodedCurrentUrl);
         } else {
-            if (!allowPreview(imgUrls.get(0))) {
-                return otherFilePreview.notSupportedFile(model, "该文件不允许预览:" + imgUrls.get(0));
-            }
             model.addAttribute("currentUrl", imgUrls.get(0));
         }
         return PICTURE_FILE_PREVIEW_PAGE;
@@ -118,12 +105,6 @@ public class OnlinePreviewController {
         logger.info("下载跨域pdf文件url:{}", urlPath);
         try {
             URL url = WebUtils.normalizedURL(urlPath);
-            if (!allowPreview(urlPath)) {
-                response.setHeader("content-type", "text/html;charset=utf-8");
-                response.getOutputStream().println("forbidden");
-                response.setStatus(401);
-                return;
-            }
             byte[] bytes = NetUtil.downloadBytes(url.toString());
             IOUtils.write(bytes, response.getOutputStream());
         } catch (IOException | GalimatiasParseException e) {
@@ -144,24 +125,6 @@ public class OnlinePreviewController {
         return "success";
     }
 
-    private boolean allowPreview(String urlPath) {
-        try {
-            URL url = WebUtils.normalizedURL(urlPath);
-            if ("file".equals(url.getProtocol().toLowerCase(Locale.ROOT))) {
-                String filePath = URLDecoder.decode(url.getPath(), StandardCharsets.UTF_8.name());
-                if (PlatformUtils.isWindows()) {
-                    filePath = filePath.replaceAll("/", "\\\\");
-                }
-                filePath = filePath.substring(1);
-                if (!filePath.startsWith(ConfigConstants.getFileDir()) && !filePath.startsWith(ConfigConstants.getLocalPreviewDir())) {
-                    return false;
-                }
-            }
-            return true;
-        } catch (IOException | GalimatiasParseException e) {
-            logger.error("解析URL异常,url:{}", urlPath, e);
-            return false;
-        }
-    }
+
 
 }

+ 0 - 65
server/src/main/java/cn/keking/web/filter/FilterConfiguration.java

@@ -1,65 +0,0 @@
-package cn.keking.web.filter;
-
-import org.springframework.boot.web.servlet.FilterRegistrationBean;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-import java.util.HashSet;
-import java.util.Set;
-
-
-/**
- *
- * @author yudian-it
- * @date 2017/11/30
- */
-@Configuration
-public class FilterConfiguration {
-
-
-    @Bean
-    public FilterRegistrationBean getChinesePathFilter() {
-        ChinesePathFilter filter = new ChinesePathFilter();
-        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
-        registrationBean.setFilter(filter);
-        return registrationBean;
-    }
-
-    @Bean
-    public FilterRegistrationBean getTrustHostFilter() {
-        Set<String> filterUri = new HashSet<>();
-        filterUri.add("/onlinePreview");
-        filterUri.add("/picturesPreview");
-        TrustHostFilter filter = new TrustHostFilter();
-        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
-        registrationBean.setFilter(filter);
-        registrationBean.setUrlPatterns(filterUri);
-        return registrationBean;
-    }
-
-    @Bean
-    public FilterRegistrationBean getBaseUrlFilter() {
-        Set<String> filterUri = new HashSet<>();
-        filterUri.add("/index");
-        filterUri.add("/onlinePreview");
-        filterUri.add("/picturesPreview");
-        BaseUrlFilter filter = new BaseUrlFilter();
-        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
-        registrationBean.setFilter(filter);
-        registrationBean.setUrlPatterns(filterUri);
-        return registrationBean;
-    }
-
-    @Bean
-    public FilterRegistrationBean getWatermarkConfigFilter() {
-        Set<String> filterUri = new HashSet<>();
-        filterUri.add("/index");
-        filterUri.add("/onlinePreview");
-        filterUri.add("/picturesPreview");
-        AttributeSetFilter filter = new AttributeSetFilter();
-        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
-        registrationBean.setFilter(filter);
-        registrationBean.setUrlPatterns(filterUri);
-        return registrationBean;
-    }
-}

+ 73 - 0
server/src/main/java/cn/keking/web/filter/TrustDirFilter.java

@@ -0,0 +1,73 @@
+package cn.keking.web.filter;
+
+import cn.keking.config.ConfigConstants;
+import cn.keking.utils.WebUtils;
+import io.mola.galimatias.GalimatiasParseException;
+import org.artofsolving.jodconverter.util.PlatformUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.util.FileCopyUtils;
+
+import javax.servlet.*;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Locale;
+
+/**
+ * @author : kl (http://kailing.pub)
+ * @since : 2022-05-25 17:45
+ */
+public class TrustDirFilter implements Filter {
+
+    private String notTrustDirView;
+    private final Logger logger = LoggerFactory.getLogger(TrustDirFilter.class);
+
+
+    @Override
+    public void init(FilterConfig filterConfig) {
+        ClassPathResource classPathResource = new ClassPathResource("web/notTrustDir.html");
+        try {
+            classPathResource.getInputStream();
+            byte[] bytes = FileCopyUtils.copyToByteArray(classPathResource.getInputStream());
+            this.notTrustDirView = new String(bytes, StandardCharsets.UTF_8);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+        String url = WebUtils.getSourceUrl(request);
+        if (!allowPreview(url)) {
+            response.getWriter().write(this.notTrustDirView);
+            response.getWriter().close();
+        } else {
+            chain.doFilter(request, response);
+        }
+    }
+
+    @Override
+    public void destroy() {
+
+    }
+
+    private boolean allowPreview(String urlPath) {
+        try {
+            URL url = WebUtils.normalizedURL(urlPath);
+            if ("file".equals(url.getProtocol().toLowerCase(Locale.ROOT))) {
+                String filePath = URLDecoder.decode(url.getPath(), StandardCharsets.UTF_8.name());
+                if (PlatformUtils.isWindows()) {
+                    filePath = filePath.replaceAll("/", "\\\\");
+                }
+                return filePath.startsWith(ConfigConstants.getFileDir()) || filePath.startsWith(ConfigConstants.getLocalPreviewDir());
+            }
+            return true;
+        } catch (IOException | GalimatiasParseException e) {
+            logger.error("解析URL异常,url:{}", urlPath, e);
+            return false;
+        }
+    }
+}

+ 3 - 29
server/src/main/java/cn/keking/web/filter/TrustHostFilter.java

@@ -1,6 +1,7 @@
 package cn.keking.web.filter;
 
 import cn.keking.config.ConfigConstants;
+import cn.keking.utils.WebUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.core.io.ClassPathResource;
 import org.springframework.util.Base64Utils;
@@ -34,11 +35,8 @@ public class TrustHostFilter implements Filter {
 
     @Override
     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
-        String url = getSourceUrl(request);
-        if(url != null){
-            url = new String(Base64Utils.decodeFromString(url), StandardCharsets.UTF_8);
-        }
-        String host = getHost(url);
+        String url = WebUtils.getSourceUrl(request);
+        String host = WebUtils.getHost(url);
         if (host != null &&!ConfigConstants.getTrustHostSet().isEmpty() && !ConfigConstants.getTrustHostSet().contains(host)) {
             String html = this.notTrustHost.replace("${current_host}", host);
             response.getWriter().write(html);
@@ -52,28 +50,4 @@ public class TrustHostFilter implements Filter {
 
     }
 
-    private String getSourceUrl(ServletRequest request) {
-        String url = request.getParameter("url");
-        String currentUrl = request.getParameter("currentUrl");
-        String urlPath = request.getParameter("urlPath");
-        if (StringUtils.isNotBlank(url)) {
-            return url;
-        }
-        if (StringUtils.isNotBlank(currentUrl)) {
-            return currentUrl;
-        }
-        if (StringUtils.isNotBlank(urlPath)) {
-            return urlPath;
-        }
-        return null;
-    }
-
-    private String getHost(String urlStr) {
-        try {
-            URL url = new URL(urlStr);
-            return url.getHost().toLowerCase();
-        } catch (MalformedURLException ignored) {
-        }
-        return null;
-    }
 }

+ 41 - 0
server/src/main/resources/web/notTrustDir.html

@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+
+<html lang="en">
+<head>
+    <meta charset="utf-8" />
+    <style type="text/css">
+        body {
+            margin: 0 auto;
+            width: 900px;
+            background-color: #CCB;
+        }
+        .container {
+            width: 700px;
+            height: 700px;
+            margin: 0 auto;
+        }
+        img {
+            width: auto;
+            height: auto;
+            max-width: 100%;
+            max-height: 100%;
+            padding-bottom: 36px;
+        }
+        p {
+            display: block;
+            font-size: 20px;
+            color: blue;
+        }
+    </style>
+</head>
+<body>
+<div class="container">
+    <img src="images/sorry.jpg" />
+    <p>
+        预览源文件来自未授信的目录 ,请停止访问 <br>
+        有任何疑问,请加&nbsp;<a href="https://jq.qq.com/?_wv=1027&k=5c0UAtu">官方QQ群:613025121</a>&nbsp;咨询
+    </p>
+</div>
+</body>
+
+</html>