From 04acf38071a95b16b368cc3349addc8613c3d37e Mon Sep 17 00:00:00 2001 From: chenrui <1950717904@qq.com> Date: Mon, 4 Nov 2024 11:31:21 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E5=85=85=E4=B8=8A=E4=BC=A0=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E7=B1=BB=E5=9E=8B=E6=8B=A6=E6=88=AA=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdditionAllowUploadFileTypes.java | 18 +++ .../auth/framework/config/FileTypeFilter.java | 115 ++++++++++++++++++ .../framework/config/FileTypeProperties.java | 88 ++++++++++++++ .../config/FileUploadConfiguration.java | 31 +++++ .../auth/framework/config/FilterConfig.java | 5 + .../framework/config/ResourcesConfig.java | 6 + 6 files changed, 263 insertions(+) create mode 100644 lib/EmergencyBaseLib/EmergencyCommon/src/main/java/com/zdxt/common/annotation/AdditionAllowUploadFileTypes.java create mode 100644 lib/EmergencyService/zdxtEmergencyAuthService/src/main/java/com/zdxt/auth/framework/config/FileTypeFilter.java create mode 100644 lib/EmergencyService/zdxtEmergencyAuthService/src/main/java/com/zdxt/auth/framework/config/FileTypeProperties.java create mode 100644 lib/EmergencyService/zdxtEmergencyAuthService/src/main/java/com/zdxt/auth/framework/config/FileUploadConfiguration.java diff --git a/lib/EmergencyBaseLib/EmergencyCommon/src/main/java/com/zdxt/common/annotation/AdditionAllowUploadFileTypes.java b/lib/EmergencyBaseLib/EmergencyCommon/src/main/java/com/zdxt/common/annotation/AdditionAllowUploadFileTypes.java new file mode 100644 index 00000000..890447d9 --- /dev/null +++ b/lib/EmergencyBaseLib/EmergencyCommon/src/main/java/com/zdxt/common/annotation/AdditionAllowUploadFileTypes.java @@ -0,0 +1,18 @@ +package com.zdxt.common.annotation; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface AdditionAllowUploadFileTypes { + String[] value() default ""; +} + + diff --git a/lib/EmergencyService/zdxtEmergencyAuthService/src/main/java/com/zdxt/auth/framework/config/FileTypeFilter.java b/lib/EmergencyService/zdxtEmergencyAuthService/src/main/java/com/zdxt/auth/framework/config/FileTypeFilter.java new file mode 100644 index 00000000..9a47f8d4 --- /dev/null +++ b/lib/EmergencyService/zdxtEmergencyAuthService/src/main/java/com/zdxt/auth/framework/config/FileTypeFilter.java @@ -0,0 +1,115 @@ +package com.zdxt.auth.framework.config; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.FileTypeUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.extra.servlet.ServletUtil; +import com.alibaba.fastjson.JSONObject; +import com.google.common.collect.Lists; +import com.zdxt.common.ZDResponse; +import com.zdxt.common.annotation.AdditionAllowUploadFileTypes; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.MediaType; +import org.springframework.lang.NonNull; +import org.springframework.messaging.handler.HandlerMethod; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.MultipartHttpServletRequest; +import org.springframework.web.servlet.HandlerInterceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; +import java.util.*; + +@Component +public class FileTypeFilter implements HandlerInterceptor { + private final FileTypeProperties fileTypeProperties; + + public FileTypeFilter(FileTypeProperties fileTypeProperties) { + this.fileTypeProperties = fileTypeProperties; + } + + @Override + public boolean preHandle(@NonNull HttpServletRequest request, + @NonNull HttpServletResponse response, + @NonNull Object handler) throws Exception { + if (!(request instanceof MultipartHttpServletRequest)) { + return true; + } + + Map allFiles = ((MultipartHttpServletRequest) request).getFileMap(); + List notAllowedFiles = getNotAllowedFiles(handler, allFiles); + + if (CollUtil.isNotEmpty(notAllowedFiles)) { + String message = "不被允许的文件类型!不被允许的文件列表如下:" + notAllowedFiles; + ServletUtil.write(response, JSONObject.toJSONString(ZDResponse.error(message)), MediaType.APPLICATION_JSON_UTF8_VALUE); + return false; + } + + return true; + } + + private List getNotAllowedFiles(Object handler, Map allFiles) throws IOException { + List notAllowedFilenames = null; + for (MultipartFile file : allFiles.values()) { + if (!isAllowedFile(file, handler)) { + if (notAllowedFilenames == null) { + notAllowedFilenames = new ArrayList<>(); + } + notAllowedFilenames.add(file.getOriginalFilename()); + } + } + return notAllowedFilenames; + } + + boolean isAllowedFile(MultipartFile file, Object handler) throws IOException { + String fileName = file.getOriginalFilename(); + try (InputStream in = file.getInputStream()) { + String type = FileTypeUtil.getType(in); + if (StringUtils.isBlank(type)) { + // 无法通过文件头或者扩展名识别文件类型。 + return false; + } + + String extType = FileUtil.extName(fileName); + if (StringUtils.isBlank(extType)) { + // 后缀读不到类型,直接拒绝 + return false; + } + + // 文件头类型和后缀类型都要满足白名单 + if (CollectionUtils.containsAll(fileTypeProperties.getAllowedTypes(), + Lists.newArrayList(type.toLowerCase(Locale.ROOT), extType.toLowerCase(Locale.ROOT)))) { + return true; + } + + String[] additionAllowUploadFileTypes = getAdditionAllowUploadFileTypes(handler); + return Arrays.stream(additionAllowUploadFileTypes) + .anyMatch(type::equalsIgnoreCase) && + Arrays.stream(additionAllowUploadFileTypes) + .anyMatch(extType::equalsIgnoreCase); + } + } + + private String[] getAdditionAllowUploadFileTypes(Object handle) { + String[] res = new String[0]; + if (!(handle instanceof HandlerMethod)) { + return res; + } + + HandlerMethod handlerMethod = (HandlerMethod) handle; + if (handlerMethod.hasMethodAnnotation(AdditionAllowUploadFileTypes.class)) { + AdditionAllowUploadFileTypes types = handlerMethod.getMethodAnnotation(AdditionAllowUploadFileTypes.class); + if (types != null) { + String[] allowedTypes = types.value(); + if (allowedTypes != null) { + res = allowedTypes; + } + } + } + return res; + } +} \ No newline at end of file diff --git a/lib/EmergencyService/zdxtEmergencyAuthService/src/main/java/com/zdxt/auth/framework/config/FileTypeProperties.java b/lib/EmergencyService/zdxtEmergencyAuthService/src/main/java/com/zdxt/auth/framework/config/FileTypeProperties.java new file mode 100644 index 00000000..3406399a --- /dev/null +++ b/lib/EmergencyService/zdxtEmergencyAuthService/src/main/java/com/zdxt/auth/framework/config/FileTypeProperties.java @@ -0,0 +1,88 @@ +package com.zdxt.auth.framework.config; + + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.google.common.collect.Lists; +import lombok.Data; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Set; + +/** + * 默认支持上传: + * 1. 文档类: "xlsx", "xls", "docx", "doc", "pdf", "txt" + * 2. 图片/视频类: "jpg", "jpeg", "png", "bmp", "mp4" + * 3. 压缩包:zip + * + * @author + */ +@Component +@ConfigurationProperties(value = "ruoyi.filetype") +public class FileTypeProperties { + private static final Logger LOGGER = LoggerFactory.getLogger(FileTypeProperties.class); + + /** + * 默认允许的文件类型 + * + * @see cn.hutool.core.io.FileTypeUtil + */ + private List defaultAllowTypes = Lists.newArrayList( + "xlsx", "xls", "docx", "doc", "pdf", "txt", + "jpg", "jpeg", "bmp", "mp4", + "zip"); + + /** + * 自定义支持的扩展类型 + * + * @see cn.hutool.core.io.FileTypeUtil + */ + private List additionalAllowTypes; + + private Set allowedTypes; + + public Set getAllowedTypes() { + return allowedTypes; + } + + public void setAllowedTypes(Set allowedTypes) { + this.allowedTypes = allowedTypes; + } + + public List getAdditionalAllowTypes() { + return additionalAllowTypes; + } + + public void setAdditionalAllowTypes(List additionalAllowTypes) { + this.additionalAllowTypes = additionalAllowTypes; + } + + @PostConstruct + public void preSetAllowedTypes() { + allowedTypes = new HashSet<>(); + + if (CollectionUtil.isNotEmpty(defaultAllowTypes)) { + for (String type : defaultAllowTypes) { + if (StrUtil.isNotBlank(type)) { + allowedTypes.add(type.toLowerCase(Locale.ROOT)); + } + } + } + if (CollectionUtil.isNotEmpty(additionalAllowTypes)) { + for (String type : additionalAllowTypes) { + if (StrUtil.isNotBlank(type)) { + allowedTypes.add(type.toLowerCase(Locale.ROOT)); + } + } + } + LOGGER.info("File Allowed Types 初始化完成!"); + } +} + diff --git a/lib/EmergencyService/zdxtEmergencyAuthService/src/main/java/com/zdxt/auth/framework/config/FileUploadConfiguration.java b/lib/EmergencyService/zdxtEmergencyAuthService/src/main/java/com/zdxt/auth/framework/config/FileUploadConfiguration.java new file mode 100644 index 00000000..3c32b18f --- /dev/null +++ b/lib/EmergencyService/zdxtEmergencyAuthService/src/main/java/com/zdxt/auth/framework/config/FileUploadConfiguration.java @@ -0,0 +1,31 @@ +package com.zdxt.auth.framework.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +//@Configuration +public class FileUploadConfiguration implements WebMvcConfigurer { + + @Bean + public WebMvcConfigurer multipartConfigurer() { + return new WebMvcConfigurer() { + @Override + public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { + // 设置媒体类型 + configurer.mediaType("json", MediaType.APPLICATION_JSON); + // 你可以继续添加更多的媒体类型 + //图片 + configurer.mediaType("png", MediaType.IMAGE_PNG); + configurer.mediaType("gif", MediaType.IMAGE_GIF); + configurer.mediaType("jpeg", MediaType.IMAGE_JPEG); + //TODO 视频 + + //文档类型 TODO doc + configurer.mediaType("pdf", MediaType.APPLICATION_PDF); + } + }; + } +} diff --git a/lib/EmergencyService/zdxtEmergencyAuthService/src/main/java/com/zdxt/auth/framework/config/FilterConfig.java b/lib/EmergencyService/zdxtEmergencyAuthService/src/main/java/com/zdxt/auth/framework/config/FilterConfig.java index 9b6894ab..7a39e7ce 100644 --- a/lib/EmergencyService/zdxtEmergencyAuthService/src/main/java/com/zdxt/auth/framework/config/FilterConfig.java +++ b/lib/EmergencyService/zdxtEmergencyAuthService/src/main/java/com/zdxt/auth/framework/config/FilterConfig.java @@ -36,6 +36,9 @@ public class FilterConfig @Autowired HostFilter hostFilter; + @Autowired + private FileTypeFilter fileTypeFilter; + @SuppressWarnings({ "rawtypes", "unchecked" }) @Bean public FilterRegistrationBean xssFilterRegistration() @@ -52,6 +55,7 @@ public class FilterConfig registration.setInitParameters(initParameters); return registration; } + @Bean public FilterRegistrationBean hostfilter() { FilterRegistrationBean registration = new FilterRegistrationBean(); @@ -61,6 +65,7 @@ public class FilterConfig registration.setOrder(1); // 值越小,Filter越靠前。 return registration; } + // @Bean // public FilterRegistrationBean corsNewFilter() { // UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); diff --git a/lib/EmergencyService/zdxtEmergencyAuthService/src/main/java/com/zdxt/auth/framework/config/ResourcesConfig.java b/lib/EmergencyService/zdxtEmergencyAuthService/src/main/java/com/zdxt/auth/framework/config/ResourcesConfig.java index b0b5a332..4cf1693b 100644 --- a/lib/EmergencyService/zdxtEmergencyAuthService/src/main/java/com/zdxt/auth/framework/config/ResourcesConfig.java +++ b/lib/EmergencyService/zdxtEmergencyAuthService/src/main/java/com/zdxt/auth/framework/config/ResourcesConfig.java @@ -23,6 +23,9 @@ public class ResourcesConfig implements WebMvcConfigurer @Value("${shiro.user.indexUrl}") private String indexUrl; + @Autowired + private FileTypeProperties fileTypeProperties; + @Autowired private RepeatSubmitInterceptor repeatSubmitInterceptor; @@ -71,5 +74,8 @@ public class ResourcesConfig implements WebMvcConfigurer "/app/thirdLogin/testLogin" ); // 除了登录放行,其他接口都token验证 + //文件类型拦截 + registry.addInterceptor(new FileTypeFilter(fileTypeProperties)); } + } \ No newline at end of file