diff --git a/src/main/java/run/halo/app/config/WebMvcAutoConfiguration.java b/src/main/java/run/halo/app/config/WebMvcAutoConfiguration.java index 807886690..e988d5e11 100644 --- a/src/main/java/run/halo/app/config/WebMvcAutoConfiguration.java +++ b/src/main/java/run/halo/app/config/WebMvcAutoConfiguration.java @@ -15,15 +15,20 @@ import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.data.domain.PageImpl; +import org.springframework.data.web.PageableHandlerMethodArgumentResolver; +import org.springframework.data.web.SortHandlerMethodArgumentResolver; import org.springframework.format.FormatterRegistry; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.util.AntPathMatcher; +import org.springframework.util.PathMatcher; +import org.springframework.web.method.HandlerMethod; import org.springframework.web.method.support.HandlerMethodArgumentResolver; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver; import run.halo.app.config.properties.HaloProperties; @@ -32,11 +37,9 @@ import run.halo.app.factory.StringToEnumConverterFactory; import run.halo.app.model.support.HaloConst; import run.halo.app.security.resolver.AuthenticationArgumentResolver; +import javax.servlet.http.HttpServletRequest; import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; +import java.util.*; import static run.halo.app.model.support.HaloConst.FILE_SEPARATOR; import static run.halo.app.model.support.HaloConst.HALO_ADMIN_RELATIVE_PATH; @@ -50,16 +53,23 @@ import static run.halo.app.utils.HaloUtils.*; */ @Slf4j @Configuration -@EnableWebMvc @ComponentScan(basePackages = "run.halo.app.controller") @PropertySource(value = "classpath:application.yaml", ignoreResourceNotFound = true, encoding = "UTF-8") -public class WebMvcAutoConfiguration implements WebMvcConfigurer { +public class WebMvcAutoConfiguration extends WebMvcConfigurationSupport { private static final String FILE_PROTOCOL = "file:///"; + private final PageableHandlerMethodArgumentResolver pageableResolver; + + private final SortHandlerMethodArgumentResolver sortResolver; + private final HaloProperties haloProperties; - public WebMvcAutoConfiguration(HaloProperties haloProperties) { + public WebMvcAutoConfiguration(PageableHandlerMethodArgumentResolver pageableResolver, + SortHandlerMethodArgumentResolver sortResolver, + HaloProperties haloProperties) { + this.pageableResolver = pageableResolver; + this.sortResolver = sortResolver; this.haloProperties = haloProperties; } @@ -80,6 +90,8 @@ public class WebMvcAutoConfiguration implements WebMvcConfigurer { @Override public void addArgumentResolvers(List resolvers) { resolvers.add(new AuthenticationArgumentResolver()); + resolvers.add(pageableResolver); + resolvers.add(sortResolver); } /** @@ -190,4 +202,54 @@ public class WebMvcAutoConfiguration implements WebMvcConfigurer { resolver.setContentType("text/html; charset=UTF-8"); registry.viewResolver(resolver); } + + @Override + protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() { + return new HaloRequestMappingHandlerMapping(haloProperties); + } + + private static class HaloRequestMappingHandlerMapping extends RequestMappingHandlerMapping { + + private final Set blackPatterns = new HashSet<>(16); + + private final PathMatcher pathMatcher; + + private final HaloProperties haloProperties; + + public HaloRequestMappingHandlerMapping(HaloProperties haloProperties) { + this.haloProperties = haloProperties; + this.initBlackPatterns(); + pathMatcher = new AntPathMatcher(); + } + + @Override + protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { + log.debug("Looking path: [{}]", lookupPath); + for (String blackPattern : blackPatterns) { + if (this.pathMatcher.match(blackPattern, lookupPath)) { + log.info("Skipped path [{}] with pattern: [{}]", lookupPath, blackPattern); + return null; + } + } + return super.lookupHandlerMethod(lookupPath, request); + } + + private void initBlackPatterns() { + String uploadUrlPattern = ensureBoth(haloProperties.getUploadUrlPrefix(), URL_SEPARATOR) + "**"; + String adminPathPattern = ensureBoth(haloProperties.getAdminPath(), URL_SEPARATOR) + "**"; + + + blackPatterns.add("/themes/**"); + blackPatterns.add("/js/**"); + blackPatterns.add("/images/**"); + blackPatterns.add("/fonts/**"); + blackPatterns.add("/css/**"); + blackPatterns.add("/assets/**"); + blackPatterns.add("/swagger-ui.html"); + blackPatterns.add("/csrf"); + blackPatterns.add("/webjars/**"); + blackPatterns.add(uploadUrlPattern); + blackPatterns.add(adminPathPattern); + } + } } diff --git a/src/main/java/run/halo/app/controller/content/ContentArchiveController.java b/src/main/java/run/halo/app/controller/content/ContentArchiveController.java index f772b7423..e734ffbf8 100644 --- a/src/main/java/run/halo/app/controller/content/ContentArchiveController.java +++ b/src/main/java/run/halo/app/controller/content/ContentArchiveController.java @@ -33,6 +33,7 @@ public class ContentArchiveController { private final StringCacheStore cacheStore; + public ContentArchiveController(PostService postService, OptionService optionService, StringCacheStore cacheStore) { @@ -41,14 +42,14 @@ public class ContentArchiveController { this.cacheStore = cacheStore; } - @GetMapping(value = "{url}/password") + @GetMapping(value = "{url:.*}/password") public String password(@PathVariable("url") String url, Model model) { model.addAttribute("url", url); return "common/template/post_password"; } - @PostMapping(value = "{url}/password") + @PostMapping(value = "{url:.*}/password") @CacheLock(traceRequest = true, expired = 2) public String password(@PathVariable("url") String url, @RequestParam(value = "password") String password) { diff --git a/src/main/java/run/halo/app/controller/content/ContentContentController.java b/src/main/java/run/halo/app/controller/content/ContentContentController.java index acbd084c1..83615753a 100644 --- a/src/main/java/run/halo/app/controller/content/ContentContentController.java +++ b/src/main/java/run/halo/app/controller/content/ContentContentController.java @@ -77,7 +77,7 @@ public class ContentContentController { } } - @GetMapping("{prefix}/page/{page}") + @GetMapping("{prefix}/page/{page:\\d+}") public String content(@PathVariable("prefix") String prefix, @PathVariable(value = "page") Integer page, Model model) { @@ -89,7 +89,7 @@ public class ContentContentController { } } - @GetMapping("{prefix}/{url}") + @GetMapping("{prefix}/{url:.+}") public String content(@PathVariable("prefix") String prefix, @PathVariable("url") String url, @RequestParam(value = "token", required = false) String token, @@ -115,7 +115,7 @@ public class ContentContentController { } } - @GetMapping("{prefix}/{url}/page/{page}") + @GetMapping("{prefix}/{url}/page/{page:\\d+}") public String content(@PathVariable("prefix") String prefix, @PathVariable("url") String url, @PathVariable("page") Integer page, @@ -132,7 +132,7 @@ public class ContentContentController { } } - // @GetMapping("{year:^[^A-Za-z]*$}/{month:^[^A-Za-z]*$}/{url}") + @GetMapping("{year:\\d+}/{month:\\d+}/{url:.+}") public String content(@PathVariable("year") Integer year, @PathVariable("month") Integer month, @PathVariable("url") String url, @@ -147,7 +147,7 @@ public class ContentContentController { } } - // @GetMapping("{year:^[^A-Za-z]*$}/{month:^[^A-Za-z]*$}/{day:^[^A-Za-z]*$}/{url}") + @GetMapping("{year:\\d+}/{month:\\d+}/{day:\\d+}/{url:.+}") public String content(@PathVariable("year") Integer year, @PathVariable("month") Integer month, @PathVariable("day") Integer day,