6 changed files with 263 additions and 0 deletions
@ -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 ""; |
|||
} |
|||
|
|||
|
|||
@ -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<String, MultipartFile> allFiles = ((MultipartHttpServletRequest) request).getFileMap(); |
|||
List<String> 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<String> getNotAllowedFiles(Object handler, Map<String, MultipartFile> allFiles) throws IOException { |
|||
List<String> 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; |
|||
} |
|||
} |
|||
@ -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<String> defaultAllowTypes = Lists.newArrayList( |
|||
"xlsx", "xls", "docx", "doc", "pdf", "txt", |
|||
"jpg", "jpeg", "bmp", "mp4", |
|||
"zip"); |
|||
|
|||
/** |
|||
* 自定义支持的扩展类型 |
|||
* |
|||
* @see cn.hutool.core.io.FileTypeUtil |
|||
*/ |
|||
private List<String> additionalAllowTypes; |
|||
|
|||
private Set<String> allowedTypes; |
|||
|
|||
public Set<String> getAllowedTypes() { |
|||
return allowedTypes; |
|||
} |
|||
|
|||
public void setAllowedTypes(Set<String> allowedTypes) { |
|||
this.allowedTypes = allowedTypes; |
|||
} |
|||
|
|||
public List<String> getAdditionalAllowTypes() { |
|||
return additionalAllowTypes; |
|||
} |
|||
|
|||
public void setAdditionalAllowTypes(List<String> 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 初始化完成!"); |
|||
} |
|||
} |
|||
|
|||
@ -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); |
|||
} |
|||
}; |
|||
} |
|||
} |
|||
Loading…
Reference in new issue