业务场景:
微信小程序需要对文本内容进行检测,保障发布内容的安全。
解决方案:
1.直接使用微信小程序的接口对文本内容进行检测
2.使用Filter来对所有请求进行拦截
3.Filter中获取请求参数的方式:
get请求:参数可以直接使用request.getParameter获取。
post请求:可以通过request.getInputStream()来获取,但是InputStream对象在被读取完成后,
将无法被再次读取,始终返回-1。可以通过继承 HttpServletRequestWrapper 类获取
request.getInputStream()中的数据
代码 :从上往下依次展示
1.自定义Filter
import com.alibaba.fastjson.JSON;
import com.leadcom.constant.AppReturnContants;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @ Author :Cz
* @ Date :Created in 16:49 2019/11/6
* @ Description:
* @ Modified By:
*/
@Component
@WebFilter(urlPatterns = "/**", filterName = "ParamsFilter", dispatcherTypes = DispatcherType.REQUEST)
public class SecFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
ParameterRequestWrapper parmsRequest = new ParameterRequestWrapper((HttpServletRequest) request);
if(!parmsRequest.getIllegal()){ //向前端提示有非法字符
response.setContentType("application/json; charset=UTF-8");
Map<String, Object> modelMap = new LinkedHashMap<String,Object>();
modelMap.put(AppReturnContants.Common.CODE, AppReturnContants.R_80000.code);
modelMap.put(AppReturnContants.Common.MSG, AppReturnContants.R_80000.message);
modelMap.put("timestamp", System.currentTimeMillis());
PrintWriter out = response.getWriter();
out.println(JSON.toJSONString(modelMap));
out.flush();
}else {
chain.doFilter(parmsRequest, response);
}
}
@Override
public void destroy() {
}
}
2.自定义ParameterRequestWrapper类继承HttpServletRequestWrapper
import com.alibaba.fastjson.JSON;
import com.leadcom.utils.SecCheckUtil;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.util.*;
/**
* @ Author :Cz
* @ Date :Created in 16:58 2019/11/6
* @ Description:
* @ Modified By:
*/
public class ParameterRequestWrapper extends HttpServletRequestWrapper {
//保存流中的数据
private byte[] data;
private Boolean illegal = true;
public ParameterRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
data = IOUtils.toByteArray(request.getInputStream());
String json = new String(data, "utf-8");
if(StringUtils.isNotBlank(json)){ //get请求json为null
Map<String, Object> map = (Map<String, Object>) JSON.parse(json);
for (Map.Entry<String, Object> entry : map.entrySet()) {
//对value进行非法字符检测:非法返回false,反之
Boolean result = SecCheckUtil.msgCheck(entry.getValue().toString());
if(!result){
illegal = false;
}
}
}
}
/**
* 在使用@RequestBody注解的时候,其实框架是调用了getInputStream()方法,所以我们要重写这个方法
* @return
* @throws IOException
*/
@Override
public ServletInputStream getInputStream() {
//在调用getInputStream函数时,创建新的流,包含原先数据流中的信息,然后返回
return new MyServletInputStream(new ByteArrayInputStream(data));
}
class MyServletInputStream extends ServletInputStream {
private InputStream inputStream;
public MyServletInputStream(InputStream inputStream) {
this.inputStream = inputStream;
}
@Override
public int read() throws IOException {
return inputStream.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener listener) {
}
}
public Boolean getIllegal() {
return illegal;
}
}
3.检测是否非法的工具类
public class SecCheckUtil {
/**
* 文本检测
* @param content
* @return
* @throws IOException
*/
public static Boolean msgCheck(String content) throws IOException {
String accessToken = getAccessToken();
return checkContent(accessToken, content);
}
public static Boolean checkContent(String accessToken, String content) throws IOException {
CloseableHttpClient httpclient = HttpClients.createDefault();
CloseableHttpResponse response = null;
HttpPost request = new HttpPost("https://api.weixin.qq.com/wxa/msg_sec_check?access_token=" + accessToken);
request.addHeader("Content-Type", "application/json");
Map<String, String> map = new HashMap<>();
map.put("content", content);
String body = JSONObject.toJSONString(map);
request.setEntity(new StringEntity(body, ContentType.create("text/json", "UTF-8")));
response = httpclient.execute(request);
HttpEntity httpEntity = response.getEntity();
String result = EntityUtils.toString(httpEntity, "UTF-8");// 转成string
JSONObject jso = JSONObject.parseObject(result);
return getResult(jso);
}
private static Boolean getResult(JSONObject jso) {
Object errcode = jso.get("errcode");
int errCode = (int) errcode;
if (errCode == 0) {
return true;
} else if (errCode == 87014) {
return false;
}
return true;
}
//获取小程序accessToken
public static String getAccessToken() {
//替换成你的appId和secret
String requestUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + WxConstants.APPLETID + "&secret=" + WxConstants.APPLETSECRET;
JSONObject jsonObject = HttpRequest.httpRequest(requestUrl, "GET", null);
return jsonObject.getString("access_token");
}
}
4.postman测试
有非法字符
没有非法字符