diff --git a/pom.xml b/pom.xml index 298707a..7988751 100644 --- a/pom.xml +++ b/pom.xml @@ -112,7 +112,6 @@ sa-token-dao-redis-jackson 1.26.0 - org.springframework.boot diff --git a/src/main/java/com/fc/v2/common/conf/xss/SimpleCORSFilter.java b/src/main/java/com/fc/v2/common/conf/xss/SimpleCORSFilter.java index cc06945..48e19be 100644 --- a/src/main/java/com/fc/v2/common/conf/xss/SimpleCORSFilter.java +++ b/src/main/java/com/fc/v2/common/conf/xss/SimpleCORSFilter.java @@ -1,7 +1,8 @@ package com.fc.v2.common.conf.xss; import java.io.IOException; - +import java.util.ArrayList; +import java.util.List; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; @@ -10,35 +11,61 @@ import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import com.fc.v2.util.StringUtils; -import org.springframework.stereotype.Component; -@Component public class SimpleCORSFilter implements Filter { - + /** + * 排除链接 + */ + public List excludes = new ArrayList<>(); + @Override - public void doFilter(ServletRequest req, ServletResponse res, - FilterChain chain) throws IOException, ServletException { - // 在这里,使用我们实现的XSS过滤器 - XssHttpServletRequestWrapper request = - new XssHttpServletRequestWrapper((HttpServletRequest) req); - - HttpServletResponse response = (HttpServletResponse) res; - response.setHeader("Access-Control-Allow-Origin", "*"); - response.setHeader("Access-Control-Allow-Methods", - "POST, GET, PUT, OPTIONS, DELETE"); - response.setHeader("Access-Control-Max-Age", "3600"); - response.setHeader("Access-Control-Allow-Headers", - "Origin, X-Requested-With, Content-Type, Accept, token"); - - chain.doFilter(request, response); + public void doFilter(ServletRequest req, ServletResponse res,FilterChain chain) throws IOException, ServletException { + // 在这里,使用我们实现的XSS过滤器 + XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) req); + HttpServletResponse response = (HttpServletResponse) res; + HttpServletRequest request = (HttpServletRequest) req; + if (handleExcludeURL(request, response)) + { + chain.doFilter(request, response); + return; + } + response.setHeader("Access-Control-Allow-Origin", "*"); + response.setHeader("Access-Control-Allow-Methods","POST, GET, PUT, OPTIONS, DELETE"); + response.setHeader("Access-Control-Max-Age", "3600"); + response.setHeader("Access-Control-Allow-Headers","Origin, X-Requested-With, Content-Type, Accept, token"); + chain.doFilter(xssRequest, response); + } public void init(FilterConfig filterConfig) { + String tempExcludes = filterConfig.getInitParameter("exclusions"); + if (StringUtils.isNotEmpty(tempExcludes)) + { + String[] url = tempExcludes.split(","); + for (int i = 0; url != null && i < url.length; i++) + { + excludes.add(url[i]); + } + } } + + private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) + { + String url = request.getServletPath(); + String method = request.getMethod(); + // GET DELETE 不过滤 + if (method == null || method.matches("GET") || method.matches("DELETE")) + { + return true; + } + return StringUtils.matches(url, excludes); + } public void destroy() { + } } \ No newline at end of file diff --git a/src/main/java/com/fc/v2/common/conf/xss/XssFilterAtuoConfig.java b/src/main/java/com/fc/v2/common/conf/xss/XssFilterAtuoConfig.java index e7b550c..bcf7780 100644 --- a/src/main/java/com/fc/v2/common/conf/xss/XssFilterAtuoConfig.java +++ b/src/main/java/com/fc/v2/common/conf/xss/XssFilterAtuoConfig.java @@ -3,12 +3,7 @@ package com.fc.v2.common.conf.xss; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fc.v2.common.conf.V2Config; - -import cn.hutool.core.util.ArrayUtil; -import cn.hutool.core.util.StrUtil; - import java.util.List; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; @@ -29,8 +24,8 @@ public class XssFilterAtuoConfig { * @return */ @Bean - public FilterRegistrationBean xssFiltrRegister() { - FilterRegistrationBean registration = new FilterRegistrationBean(); + public FilterRegistrationBean xssFiltrRegister() { + FilterRegistrationBean registration = new FilterRegistrationBean(); //设置系统过滤器 (setFilter就是你所定义的过滤器filter类) registration.setFilter(new SimpleCORSFilter()); @@ -45,12 +40,11 @@ public class XssFilterAtuoConfig { if(xssnoturlList!=null&&xssnoturlList.size()>0) { xssnot=String.join(",", xssnoturlList); } - - //添加忽略的格式以及链接请求 registration.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid2/*,"+xssnot); //优先级 registration.setOrder(1); + return registration; } diff --git a/src/main/java/com/fc/v2/common/exception/GlobalExceptionResolver.java b/src/main/java/com/fc/v2/common/exception/GlobalExceptionResolver.java index f06dbfe..4ffec70 100644 --- a/src/main/java/com/fc/v2/common/exception/GlobalExceptionResolver.java +++ b/src/main/java/com/fc/v2/common/exception/GlobalExceptionResolver.java @@ -1,19 +1,24 @@ package com.fc.v2.common.exception; +import java.util.List; + import javax.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.AntPathMatcher; import org.springframework.validation.BindException; import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.servlet.ModelAndView; +import com.alibaba.fastjson.JSON; +import com.fc.v2.common.conf.V2Config; import com.fc.v2.common.domain.AjaxResult; import com.fc.v2.common.exception.demo.DemoModeException; import com.fc.v2.util.ServletUtils; - import cn.dev33.satoken.exception.NotLoginException; import cn.dev33.satoken.exception.NotPermissionException; import cn.dev33.satoken.exception.NotRoleException; @@ -29,6 +34,9 @@ import cn.dev33.satoken.exception.SaTokenException; public class GlobalExceptionResolver{ private static Logger logger = LoggerFactory.getLogger(GlobalExceptionResolver.class); + @Autowired + private V2Config v2Config; + /** * 权限校验失败 如果请求为ajax返回json,普通请求跳转页面 */ @@ -45,10 +53,24 @@ public class GlobalExceptionResolver{ { // 登录认证异常 if(e instanceof NotLoginException){ + List satoken_not_urls=v2Config.getSaTokenNotFilterUrl(); + for (String nourl : satoken_not_urls) { + AntPathMatcher matcher = new AntPathMatcher(); + if(matcher.match(nourl,request.getRequestURI())) { + return JSON.toJSONString(AjaxResult.error(886,e.getMessage())); + } + } return new ModelAndView("/login"); } // 权限认证异常 else if (e instanceof NotPermissionException || e instanceof NotRoleException || e instanceof NotSafeException){ + List satoken_not_urls=v2Config.getSaTokenNotFilterUrl(); + for (String nourl : satoken_not_urls) { + AntPathMatcher matcher = new AntPathMatcher(); + if(matcher.match(nourl,request.getRequestURI())) { + return JSON.toJSONString(AjaxResult.error(403,e.getMessage())); + } + } return new ModelAndView("/error/403"); } // 其它异常 diff --git a/src/main/java/com/fc/v2/controller/admin/goview/GoviewProjectAPi.java b/src/main/java/com/fc/v2/controller/admin/goview/GoviewProjectAPi.java index 849b2b7..84840f0 100644 --- a/src/main/java/com/fc/v2/controller/admin/goview/GoviewProjectAPi.java +++ b/src/main/java/com/fc/v2/controller/admin/goview/GoviewProjectAPi.java @@ -6,7 +6,6 @@ import com.fc.v2.common.domain.ResultTable; import com.fc.v2.model.auto.GoviewProject; import com.fc.v2.model.auto.GoviewProjectData; import com.fc.v2.model.auto.GoviewProjectDataExample; -import com.fc.v2.model.auto.GoviewProjectExample; import com.fc.v2.model.custom.Tablepar; import com.fc.v2.service.GoviewProjectDataService; import com.fc.v2.service.GoviewProjectService; @@ -14,9 +13,7 @@ import com.github.pagehelper.PageInfo; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import cn.dev33.satoken.annotation.SaCheckPermission; - import java.util.List; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; @@ -171,7 +168,7 @@ public class GoviewProjectAPi extends BaseController{ @ApiOperation(value = "保存项目数据", notes = "保存项目数据") @PostMapping("/save/data") @ResponseBody - public AjaxResult saveData(@RequestBody GoviewProjectData data) { + public AjaxResult saveData(GoviewProjectData data) { GoviewProject goviewProject= goviewProjectService.selectByPrimaryKey(data.getProjectId()); if(goviewProject==null) { diff --git a/src/main/java/com/fc/v2/satoken/SaTokenConfigure.java b/src/main/java/com/fc/v2/satoken/SaTokenConfigure.java index c3f2d61..72a1b33 100644 --- a/src/main/java/com/fc/v2/satoken/SaTokenConfigure.java +++ b/src/main/java/com/fc/v2/satoken/SaTokenConfigure.java @@ -86,6 +86,11 @@ public class SaTokenConfigure implements WebMvcConfigurer { .setError(e -> { // e.printStackTrace(); if(e instanceof NotLoginException) { + for (String nourl : satoken_not_urls) { + if(nourl.contains(SaHolder.getRequest().getUrl())) { + return JSON.toJSONString(AjaxResult.error(886,e.getMessage())); + } + } SaHolder.getResponse().redirect("/admin/login"); } return JSON.toJSONString(AjaxResult.error(e.getMessage())); diff --git a/src/main/java/com/fc/v2/util/StringUtils.java b/src/main/java/com/fc/v2/util/StringUtils.java index a042875..b77f9dc 100644 --- a/src/main/java/com/fc/v2/util/StringUtils.java +++ b/src/main/java/com/fc/v2/util/StringUtils.java @@ -1,9 +1,11 @@ package com.fc.v2.util; import java.util.Collection; +import java.util.List; import java.util.Map; import org.apache.commons.lang.WordUtils; import org.apache.commons.lang.text.StrBuilder; +import org.springframework.util.AntPathMatcher; @@ -441,4 +443,42 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils } return columnToJava(tableName); } + /** + * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串 + * + * @param str 指定字符串 + * @param strs 需要检查的字符串数组 + * @return 是否匹配 + */ + public static boolean matches(String str, List strs) + { + if (isEmpty(str) || isEmpty(strs)) + { + return false; + } + for (String pattern : strs) + { + if (isMatch(pattern, str)) + { + return true; + } + } + return false; + } + /** + * 判断url是否与规则配置: + * ? 表示单个字符; + * * 表示一层路径内的任意字符串,不可跨层级; + * ** 表示任意层路径; + * + * @param pattern 匹配规则 + * @param url 需要匹配的url + * @return + */ + public static boolean isMatch(String pattern, String url) + { + AntPathMatcher matcher = new AntPathMatcher(); + return matcher.match(pattern, url); + } + } \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 4982de4..0446723 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -20,7 +20,7 @@ fuce: #漂亮得拖动验证码 默认false普通验证码、true滚动验证码 roll-verification: false #xss不拦截url - xss-not-filter-url: [/api/v1/token/api_token,/api/v1/yibaotong/save] + xss-not-filter-url: [/api/v1/token/api_token,/api/goview/project/save/data] #satoken不拦截url sa-token-not-filter-url: [/api/goview/sys/*,/api/goview/project/**] #tomcat config