@WebFilter({"/*"})
package com.sf.gis.boot.filter; import com.alibaba.fastjson.JSON; import com.sf.gis.common.constants.CommonConstant; import com.sf.gis.common.domain.vo.user.TokenInfoVo; import com.sf.gis.common.utils.JWTUtil; import com.sf.gis.common.utils.TokenThreadLocal; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.util.AntPathMatcher; import org.springframework.util.StringUtils; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Arrays; import java.util.HashMap; import java.util.Map; @Slf4j @WebFilter({"/*"}) public class CheckTokenFilter implements Filter { @Value("${check.white-list}") private String whiteList; @Value("${jwt.thirdparty_key}") private String thirdpartyKey; @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse; httpServletResponse.setContentType("application/json;charset=utf-8"); String url = httpServletRequest.getRequestURI(); boolean match = filterPath(url); if (match) { log.info("白名单直接放行url={}", url); filterChain.doFilter(servletRequest, servletResponse); return; } String token = httpServletRequest.getHeader(CommonConstant.TOKEN); String authModel = httpServletRequest.getHeader(CommonConstant.TOKEN_MODEL); //没有token if (!StringUtils.hasLength(token)) { Map<String, String> map = new HashMap<>(); map.put("code", "401"); map.put("msg", "请先登录"); log.error("token-check: tokenInfoVo no have token: url: {}", url); String string = JSON.toJSONString(map); httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value()); httpServletResponse.getWriter().write(string); return; } //判断token是否过期 TokenInfoVo tokenInfoVo = null; boolean flag = false; try { // 第三方鉴权: header请求头中添加 x-auth-model 参数并且只为2 表示第三方请求,按照第三方的秘钥加解密token if("2".equals(authModel) && org.apache.commons.lang3.StringUtils.isNotBlank(thirdpartyKey)) { tokenInfoVo = JWTUtil.getJWTUtil().parseToken(token,thirdpartyKey); } else { tokenInfoVo = JWTUtil.getJWTUtil().parseToken(token); } Long exp = Long.valueOf(tokenInfoVo.getExp()); log.error("token-check: tokenInfoVo.getExp 过期时间:exp: {}, url: {}, token: {}", exp, url, token); long nowTime = System.currentTimeMillis() / 1000; log.error("token-check: tokenInfoVo.getExp nowTime:exp: {}, url: {}, token: {}", nowTime, url, token); if (exp < nowTime) { flag = true; log.error("token-check: false-tokenInfoVo.getExp exp <= nowTime:true, url:{}, token:{}", url, token); } } catch (Exception e) { flag = true; log.error("token-check: false-token解析失败:url:{},token:{}", url, token, e); } if (flag) { Map<String, String> map = new HashMap<>(); map.put("code", "401"); map.put("msg", "token不存在或已过期"); String string = JSON.toJSONString(map); log.error("token-check: false-tokenInfoVo parse error:url:{},token:{}", url, token); httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value()); httpServletResponse.getWriter().write(string); return; } TokenThreadLocal.set(token); try { filterChain.doFilter(servletRequest, servletResponse); } finally { TokenThreadLocal.remove(); } } /** * 校验路径 */ private boolean filterPath(String url) { AntPathMatcher pathMatcher = new AntPathMatcher(); pathMatcher.setCaseSensitive(false); String[] ignoredUrls= whiteList.split(","); boolean flag = false; for (String ignoredUrl : ignoredUrls) { flag = pathMatcher.match(ignoredUrl, url); if (flag) { break; } } return flag; } @Override public void destroy() { Filter.super.destroy(); } }
package com.sf.gis.boot.filter; import cn.hutool.core.util.StrUtil; import com.sf.gis.common.constants.CommonConstant; import com.sf.gis.common.domain.vo.user.TokenInfoVo; import com.sf.gis.common.utils.JWTUtil; import com.sf.gis.common.utils.TokenThreadLocal; import lombok.extern.slf4j.Slf4j; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Slf4j @WebFilter({"/*"}) public class RefreshTokenFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse; String url = httpServletRequest.getRequestURI(); //判断token是否即将过期:过期时间 - 当前时间 <= 15分钟 int interval = 15; String token = httpServletRequest.getHeader(CommonConstant.TOKEN); if (StrUtil.isNotBlank(token) && !"null".equals(token)) { TokenInfoVo tokenInfoVo = null; boolean isExpired = false; try { tokenInfoVo = JWTUtil.getJWTUtil().parseToken(token); Long exp = Long.valueOf(tokenInfoVo.getExp()); long nowTime = System.currentTimeMillis() / 1000; if ((exp - nowTime) / 60 <= interval) { isExpired = true; } } catch (Exception e) { isExpired = true; log.error("token-check:exp token解析失败, url:{}, token:{}", url, token, e); } //添加刷新标识 if (isExpired) { log.error("token-check:exp tokenInfoVo parse error: url:{}, token:{}}", url, token); httpServletResponse.setHeader("x-refresh-token", "true"); } } filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { Filter.super.destroy(); } }
package com.sf.gis.boot.filter; import com.alibaba.fastjson.JSONObject; import com.sf.gis.common.utils.SM4Utils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; import org.springframework.util.AntPathMatcher; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.util.Enumeration; import java.util.HashSet; import java.util.Set; /** * 过滤器拦截请求,实现对请求参数的解密功能 */ @Slf4j @Component public class DecryptFilter implements Filter { //不需要加密的接口 @Value("${req.ignoreDecryptUrl}") private String ignoreDecryptUrl; @Value("${res.encryptKey}") private String decryptKey; @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse response, FilterChain chain) throws IOException, ServletException { try { HttpServletRequest request = (HttpServletRequest) servletRequest; RequestWrapper requestWrapper = new RequestWrapper((HttpServletRequest) request); String method = request.getMethod(); String url = request.getRequestURI(); log.info("请求参数的解密,请求路径={}", url); Boolean flag = false; String contentType = request.getContentType(); /*if (StringUtils.isNotEmpty(contentType) && contentType.contains("multipart/form-data")) { String contentDisposition = requestWrapper.getHeader("Content-Disposition"); if (StringUtils.isNotBlank(contentDisposition)) { log.info("上传文件Content-Disposition:{}", contentDisposition); } if (StringUtils.isNotBlank(contentType)) { log.info("上传文件contentType:{}", contentType); } Enumeration<String> em = requestWrapper.getHeaderNames(); while (em.hasMoreElements()) { String str = em.nextElement(); if (StringUtils.isNotBlank(str)) { String headerValue = requestWrapper.getHeader(str); if (StringUtils.isNotBlank(headerValue)) { log.info("上传文件headerName:{},headerValue:{}", str,headerValue); } } } }*/ //判断是否是静态资源 if (isStaticResource(url)) { flag = true; } else { url = url.split("\\?")[0]; AntPathMatcher pathMatcher = new AntPathMatcher(); pathMatcher.setCaseSensitive(false); String[] ignoredUrls = ignoreDecryptUrl.split(","); for (String ignoredUrl : ignoredUrls) { flag = pathMatcher.match(ignoredUrl, url); if (flag) { break; } } } if (!flag) { if (!"POST".equals(method)) { response.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter(); out.print("只允许使用POST请求方式"); out.flush(); out.close(); } // 该方法处理 POST请求并且contentType为application/json格式的 if ("POST".equals(method) && StringUtils.isNotEmpty(contentType) && contentType.contains(MediaType.APPLICATION_JSON_VALUE)) { String str = new String(requestWrapper.getBody()); if (StringUtils.isNotBlank(str) && !"null".equals(str) && !"{}".equals(str)) { JSONObject jsonObject = JSONObject.parseObject(str); if (!jsonObject.containsKey("body")) { response.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter(); out.print("请求实体必须包含body,如:{\"body\":\"加密串\"}"); out.flush(); out.close(); } else { if (null == jsonObject.get("body")) { chain.doFilter(requestWrapper, response); } else { String bodyStr = jsonObject.get("body").toString(); if (StringUtils.isBlank(bodyStr)) { chain.doFilter(requestWrapper, response); } else { //post请求内容需要解密 str = SM4Utils.getsM4Utils().strDecode(bodyStr, decryptKey); requestWrapper.setBody(str.getBytes(StandardCharsets.UTF_8)); chain.doFilter(requestWrapper, response); } } } } else { // 继续处理请求 chain.doFilter(requestWrapper, response); } } else { // 继续处理请求 chain.doFilter(requestWrapper, response); } } else { chain.doFilter(requestWrapper, response); } } catch (Exception e) { log.error("DecryptFilter解密失败", e); } } /* private void setPostParameterMap(Map<String, String[]> decryptedParameterMap, String decryptedValues) { getJsonObject(decryptedParameterMap, decryptedValues); } private void getJsonObject(Map<String, String[]> decryptedParameterMap, String decryptedValues) { JSONObject jsonObject = JSONObject.parseObject(decryptedValues); if (Objects.nonNull(jsonObject)) { if (jsonObject.size() > 0) { String body = jsonObject.getString("body"); if (body.startsWith("[")) { String[] params = new String[1]; params[0] = body; decryptedParameterMap.put("param", params); } else { JSONObject parseObject = JSONObject.parseObject(body); Set<String> strings = parseObject.keySet(); for (String string : strings) { String[] params = new String[1]; params[0] = parseObject.getString(string); //数组参数处理 if (params[0].contains("[")) { String[] res = JSONObject.parseObject(params[0], String[].class); decryptedParameterMap.put(string, res); } else { decryptedParameterMap.put(string, params); } } } } } } private void setParameterMap(Map<String, String[]> decryptedParameterMap, String decryptedValues) { getJsonObject(decryptedParameterMap, decryptedValues); }*/ @Override public void destroy() { } private Set<String> staticResourceTypes = new HashSet<String>(); { staticResourceTypes.add(".html"); staticResourceTypes.add(".css"); staticResourceTypes.add(".js"); staticResourceTypes.add(".png"); staticResourceTypes.add(".jpg"); staticResourceTypes.add(".otf"); staticResourceTypes.add(".eot"); staticResourceTypes.add(".svg"); staticResourceTypes.add(".ttf"); staticResourceTypes.add(".woff"); staticResourceTypes.add(".gif"); staticResourceTypes.add(".ico"); staticResourceTypes.add(".txt"); staticResourceTypes.add(".gzip"); staticResourceTypes.add(".xz"); staticResourceTypes.add(".tar.gz"); staticResourceTypes.add(".tar.bz2"); staticResourceTypes.add(".jar"); staticResourceTypes.add(".war"); staticResourceTypes.add(".7z"); staticResourceTypes.add(".tgz"); staticResourceTypes.add(".gz"); staticResourceTypes.add(".map"); } public final boolean isStaticResource(String url) { boolean result = false; if (StringUtils.isBlank(url)) { return result; } int start = url.lastIndexOf("."); if (start < 0) { return result; } String prex = url.substring(start, url.length()); return staticResourceTypes.contains(prex); } }
package com.sf.gis.boot.filter; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.sf.gis.common.utils.SM4Utils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.util.AntPathMatcher; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; /** * 过滤器拦截请求,实现接口响应数据加密功能 * * @Component 将此Filter交给Spring容器管理 * @WebFilter 通过WebFilter进行Filter声明,这样容器在进行部署的时候就会处理该Filter * */ @Slf4j @Component public class EncryptFilter implements Filter { @Value("${res.ignoreEncryptUrl}") private String ignoreEncryptUrl; @Value("${res.encryptKey}") private String encryptKey; @Override public void init(FilterConfig filterConfig) throws ServletException { // TODO Auto-generated method stub } /** * 有错误相应返回-44 * * @param response */ private void getFailResponse(HttpServletResponse response) throws IOException { response.setCharacterEncoding("UTF-8"); response.setContentType("application/json; charset=utf-8"); PrintWriter out = null; out = response.getWriter(); //加密后的错误消息 out.write("服务器异常,接口返回值加密异常!"); out.flush(); out.close(); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { HttpServletRequest httpRequest=(HttpServletRequest)request; HttpServletResponse httpResponse=(HttpServletResponse)response; httpResponse.setCharacterEncoding("UTF-8"); boolean flag=isIgnore2(httpRequest,ignoreEncryptUrl); if(flag || 200!=httpResponse.getStatus()) { try { chain.doFilter(request, httpResponse); } catch (Exception e) { log.error("EncryptFilter过滤器异常",e); } }else{ try{ //响应处理 包装响应对象 res 并缓存响应数据 ResponseWrapper responseWrapper = new ResponseWrapper((HttpServletResponse) response); //执行业务逻辑 交给下一个过滤器或servlet处理 chain.doFilter(request, responseWrapper); byte[] resData = responseWrapper.getResponseData(); String resStr=new String(resData); //把转成json,判断是否包含result节点,包含则对result里面的数据进行加密,否则原样返回 JSONObject json=JSON.parseObject(resStr); if(json!=null && json.containsKey("result")){ Object item = json.get("result"); //先判断是不是Json串,如果不是的话 if(item == null){ chain.doFilter(request, responseWrapper); }else{ if(!getJSONType(String.valueOf(item))){ json.put("result",SM4Utils.getsM4Utils().strEncode(String.valueOf(item),encryptKey)); handleOutPut((HttpServletResponse) response,json.toString()); }else{ String result=""; if(item instanceof JSONArray){ result=json.getJSONArray("result").toJSONString(); }else{ result=json.getJSONObject("result").toJSONString(); } result=SM4Utils.getsM4Utils().strEncode(result,encryptKey); json.put("result",result); handleOutPut((HttpServletResponse) response,json.toString()); } } }else{ handleOutPut((HttpServletResponse) response,resStr); } }catch(Exception e){ try { getFailResponse((HttpServletResponse)response); } catch (IOException ex) { log.error("EncryptFilter过滤器处理接口返回值加密失败返回异常",e); } log.error("EncryptFilter过滤器处理接口返回值加密异常",e); } } } @Override public void destroy() { // TODO Auto-generated method stub } public static boolean getJSONType(String str) { boolean result = false; if (StringUtils.isNotBlank(str)) { str = str.trim(); if (str.startsWith("{") && str.endsWith("}")) { result = true; } else if (str.startsWith("[") && str.endsWith("]")) { result = true; } } return result; } /** * 哪些路径不处理 * @param request * @param * @return */ public boolean isIgnore(HttpServletRequest request,String ignoreEncryptUrl) { if(StringUtils.isBlank(ignoreEncryptUrl)){ return false; } String[] attr= ignoreEncryptUrl.split(","); String path=request.getRequestURI(); for(String ignore:attr) { if(path.contains(ignore)) { return true; } } return false; } public boolean isIgnore2(HttpServletRequest request,String ignoreEncryptUrl) { if(StringUtils.isBlank(ignoreEncryptUrl)){ return false; } String url=request.getRequestURI(); url = url.split("\\?")[0]; log.info("响应数据加密,请求路径={}",url); AntPathMatcher pathMatcher = new AntPathMatcher(); pathMatcher.setCaseSensitive(false); String[] ignoredUrls=ignoreEncryptUrl.split(","); for (String ignoredUrl : ignoredUrls) { boolean flag = pathMatcher.match(ignoredUrl, url); if (flag) { return flag; } } return false; } private void handleOutPut(HttpServletResponse response,String resResult) throws Exception{ PrintWriter out = response.getWriter(); out.print(resResult); out.flush(); out.close(); } }