|
@@ -0,0 +1,259 @@
|
|
|
+package com.qrservice.admin.filter;
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.alibaba.fastjson.TypeReference;
|
|
|
+import com.alibaba.fastjson.parser.Feature;
|
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
+import com.google.common.cache.Cache;
|
|
|
+import com.qrservice.admin.dao.settle.InstitutionUserDao;
|
|
|
+import com.qrservice.admin.dao.settle.UserOperateLogDao;
|
|
|
+import com.qrservice.admin.exception.CheckException;
|
|
|
+import com.qrservice.admin.model.manage.InstitutionUser;
|
|
|
+import com.qrservice.admin.model.manage.UserOperateLog;
|
|
|
+import com.qrservice.admin.model.vo.ResultVO;
|
|
|
+import com.qrservice.admin.util.CacheUtil;
|
|
|
+import com.qrservice.admin.util.jwtUtil;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.slf4j.MDC;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.core.Ordered;
|
|
|
+import org.springframework.data.mongodb.core.query.Criteria;
|
|
|
+import org.springframework.data.mongodb.core.query.Query;
|
|
|
+import org.springframework.http.MediaType;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
+import org.springframework.web.bind.annotation.CrossOrigin;
|
|
|
+import org.springframework.web.filter.OncePerRequestFilter;
|
|
|
+import org.springframework.web.util.ContentCachingResponseWrapper;
|
|
|
+
|
|
|
+import javax.servlet.FilterChain;
|
|
|
+import javax.servlet.ServletException;
|
|
|
+import javax.servlet.http.HttpServletRequest;
|
|
|
+import javax.servlet.http.HttpServletResponse;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.PrintWriter;
|
|
|
+import java.io.UnsupportedEncodingException;
|
|
|
+import java.net.URLDecoder;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.Enumeration;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.TreeMap;
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * @author kang.wang
|
|
|
+ * @date 2019/07/24
|
|
|
+ **/
|
|
|
+@Slf4j
|
|
|
+//@Component
|
|
|
+public class AccessLogFilter extends OncePerRequestFilter implements Ordered {
|
|
|
+ private Integer payloadMaxLength = 2048;
|
|
|
+ /**
|
|
|
+ * put filter at the end of all other filters to make sure we are processing after all others
|
|
|
+ */
|
|
|
+ private int order = Ordered.LOWEST_PRECEDENCE - 8;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public int getOrder() {
|
|
|
+ return order;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private UserOperateLogDao dao;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private InstitutionUserDao userDao;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
|
|
|
+ FilterChain filterChain) throws ServletException, IOException {
|
|
|
+ Map<String, String[]> pm = request.getParameterMap();
|
|
|
+ ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);
|
|
|
+ ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);
|
|
|
+ long startTime = System.currentTimeMillis();
|
|
|
+ try {
|
|
|
+ // 得到用户个人相关的信息(登陆的用户,用户的语言)
|
|
|
+ if(!request.getRequestURI().contains("login") && !request.getMethod().equals("OPTIONS")
|
|
|
+ &&!request.getRequestURI().contains("export")
|
|
|
+ &&!request.getRequestURI().contains("downLoad")){
|
|
|
+ fillUserInfo(request);
|
|
|
+ }
|
|
|
+ } catch (CheckException e) {
|
|
|
+ response.setCharacterEncoding("UTF-8");
|
|
|
+ response.setContentType("application/json; charset=utf-8");
|
|
|
+ response.setHeader("Access-Control-Allow-Origin", "*");
|
|
|
+ response.setHeader("Cache-Control","no-cache");
|
|
|
+ PrintWriter out = response.getWriter();
|
|
|
+ ResultVO<String> result = new ResultVO<>();
|
|
|
+ result.setStatus("Failed");
|
|
|
+ result.setMessage("登录超时,请重新登录");
|
|
|
+ log.info("登录超时,请重新登录");
|
|
|
+ String jsonString = JSON.toJSONString(result);
|
|
|
+ out.append(jsonString);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ filterChain.doFilter(requestWrapper, responseWrapper);
|
|
|
+ //排除预请求
|
|
|
+ if(!request.getMethod().equals("OPTIONS")){
|
|
|
+ log.info(request.getServletPath() + ": 请求开始");
|
|
|
+ String requestPayload = new String(requestWrapper.getBody());
|
|
|
+ log.debug("res-contentType " + responseWrapper.getContentType());
|
|
|
+ String responsePayload = "";
|
|
|
+ if(responseWrapper.getContentType()!=null &&responseWrapper.getContentType().startsWith("application/json")){
|
|
|
+ responsePayload = getPayLoad(responseWrapper.getContentAsByteArray(),
|
|
|
+ response.getCharacterEncoding());
|
|
|
+ }
|
|
|
+ responseWrapper.copyBodyToResponse();
|
|
|
+ String method = request.getMethod();
|
|
|
+ if ("GET".equals(method)) {
|
|
|
+ String queryString = request.getQueryString();
|
|
|
+ if (queryString != null) {
|
|
|
+ requestPayload = URLDecoder.decode(queryString, "utf-8");
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ log.debug("ContentType:" + request.getContentType());
|
|
|
+ if (MediaType.APPLICATION_FORM_URLENCODED_VALUE.equals(request.getContentType())) {
|
|
|
+ Map<String, String[]> parameterMap = request.getParameterMap();
|
|
|
+ requestPayload = JSON.toJSONString(parameterMap);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ String time = System.currentTimeMillis() - startTime + "ms";
|
|
|
+ String ip = getIp(request);
|
|
|
+ String url = request.getRequestURL().toString();
|
|
|
+ log.info("请求开始============》ip: {},url: {}, method: {}, uri: {}, params: {},time: {}",ip, url, method, request.getRequestURI(), requestPayload,time);
|
|
|
+ log.info("响应:" + responsePayload);
|
|
|
+ //获取所有请求头信息
|
|
|
+ Enumeration<String> headerNames = request.getHeaderNames();
|
|
|
+ String logHeads="";
|
|
|
+ while (headerNames.hasMoreElements()) {
|
|
|
+ String name = headerNames.nextElement();
|
|
|
+ //根据名称获取请求头的值
|
|
|
+ String value = request.getHeader(name);
|
|
|
+ logHeads=name+"---"+value +'\n'+ logHeads;
|
|
|
+ }
|
|
|
+ Map jsonObject = null;
|
|
|
+ try {
|
|
|
+ jsonObject = JSON.parseObject(responsePayload,new TypeReference<TreeMap<String, String>>(){} , Feature.OrderedField);
|
|
|
+ } catch (Exception e) {
|
|
|
+ }
|
|
|
+ //打印日志信息
|
|
|
+ if(jsonObject!=null && jsonObject.containsKey("title") ){
|
|
|
+ saveLogInfo(request,ip,url,method,request.getRequestURI(),requestPayload,logHeads,responsePayload);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void saveLogInfo(HttpServletRequest request ,String ip,String url,String method,String uri,String requestPayload,String logHeads,String responsePayload) {
|
|
|
+ UserOperateLog info = new UserOperateLog();
|
|
|
+ Map vo= null;
|
|
|
+ try {
|
|
|
+ vo = JSON.parseObject(responsePayload,new TypeReference<TreeMap<String, String>>(){} , Feature.OrderedField);
|
|
|
+ } catch (Exception e) {
|
|
|
+ }
|
|
|
+ String title = vo.get("title").toString();
|
|
|
+ info.setTitle(title);
|
|
|
+ SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
|
+ info.setSystemDate(df.format(new Date()));
|
|
|
+ info.setLogs("请求开始============》ip: "+ip+",url: "+url+", method: "+method+", uri: "+uri+", params: "+requestPayload+"");
|
|
|
+ info.setLogsHead(logHeads);
|
|
|
+ info.setLogLevel(1);
|
|
|
+ info.setMessage(vo.get("message").toString());
|
|
|
+ info.setLogSource("机构平台");
|
|
|
+ info.setOperateStatus(vo.get("status").toString());
|
|
|
+ info.setModule(uri);
|
|
|
+ info.setCreateTime(new Date());
|
|
|
+ if(uri.contains("login")){
|
|
|
+ String userId = title.substring(21, title.length() - 6);
|
|
|
+ info.setUserId(userId);
|
|
|
+ Query query = new Query();
|
|
|
+ query.addCriteria(Criteria.where("userId").is(userId));
|
|
|
+ InstitutionUser one = userDao.findOne(query);
|
|
|
+ if(one!=null){
|
|
|
+ info.setInstitutionCode(one.getInstitutionCode());
|
|
|
+ }
|
|
|
+ }else {
|
|
|
+ String token = request.getHeader("Authorization");
|
|
|
+ info.setUserId(jwtUtil.getUserId(token));
|
|
|
+ info.setInstitutionCode(request.getHeader("institutionCode"));
|
|
|
+ }
|
|
|
+ dao.insert(info);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getPayLoad(byte[] buf, String characterEncoding) {
|
|
|
+ String payload = "";
|
|
|
+ if (buf == null) {
|
|
|
+ return payload;
|
|
|
+ }
|
|
|
+ if (buf.length > 0) {
|
|
|
+ int length = Math.min(buf.length, getPayloadMaxLength());
|
|
|
+ try {
|
|
|
+ payload = new String(buf, 0, length, characterEncoding);
|
|
|
+ } catch (UnsupportedEncodingException ex) {
|
|
|
+ payload = "[unknown]";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return payload;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Integer getPayloadMaxLength() {
|
|
|
+ return payloadMaxLength;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setPayloadMaxLength(Integer payloadMaxLength) {
|
|
|
+ this.payloadMaxLength = payloadMaxLength;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private String getIp(HttpServletRequest request) {
|
|
|
+ String ip = null;
|
|
|
+ //X-Forwarded-For:Squid 服务代理
|
|
|
+ String ipAddresses = request.getHeader("X-Forwarded-For");
|
|
|
+
|
|
|
+ if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
|
|
|
+ //Proxy-Client-IP:apache 服务代理
|
|
|
+ ipAddresses = request.getHeader("Proxy-Client-IP");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
|
|
|
+ //WL-Proxy-Client-IP:weblogic 服务代理
|
|
|
+ ipAddresses = request.getHeader("WL-Proxy-Client-IP");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
|
|
|
+ //HTTP_CLIENT_IP:有些代理服务器
|
|
|
+ ipAddresses = request.getHeader("HTTP_CLIENT_IP");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
|
|
|
+ //X-Real-IP:nginx服务代理
|
|
|
+ ipAddresses = request.getHeader("X-Real-IP");
|
|
|
+ }
|
|
|
+
|
|
|
+ //有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP
|
|
|
+ if (ipAddresses != null && ipAddresses.length() != 0) {
|
|
|
+ ip = ipAddresses.split(",")[0];
|
|
|
+ }
|
|
|
+ //还是不能获取到,最后再通过request.getRemoteAddr();获取
|
|
|
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
|
|
|
+ ip = request.getRemoteAddr();
|
|
|
+ }
|
|
|
+ return ip;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void fillUserInfo(HttpServletRequest request) {
|
|
|
+ //判断用户token是否过期,以及是否重复登录
|
|
|
+ String tokenFront = request.getHeader("Authorization");
|
|
|
+ String userId = jwtUtil.getUserId(tokenFront);
|
|
|
+ String userName = jwtUtil.getUserName(tokenFront);
|
|
|
+ Cache<String, String> cache = CacheUtil.getCache();
|
|
|
+ String token = cache.getIfPresent(userId);
|
|
|
+ if(token == null){
|
|
|
+ throw new CheckException("登录超时,请重新登录");
|
|
|
+ }
|
|
|
+ if(!token.equals(tokenFront)){
|
|
|
+ throw new CheckException("账户已在其他设备登录");
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|