综合性的拦截器 1.过滤敏感字符 2.解析验签注解 3.解析token注解

1.拦截器

package com.sys.interceptor;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.apache.shiro.authz.annotation.Logical;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.alibaba.druid.support.logging.Log;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.api.base.enums.ChannelTypeEnum;
import com.api.base.vo.BaseVO;
import com.common.utils.AESUtil;
import com.common.utils.SignVerifyUtil;
import com.common.utils.StringUtil;
import com.common.utils.WebConfigUtil;
import com.sys.annotation.VerifySign;
import com.sys.user.entity.User;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

/**
 * 
 *  综合性的拦截器 1.过滤敏感字符 2.解析验签注解 3.解析token注解
 */
public class SystemHandlerInterceptor extends HandlerInterceptorAdapter {
	private final Logger log = Logger.getLogger(this.getClass());
	
	@Autowired
	private JedisPool jedisPool;
	// 排除的urls
	private static List<String> list;
	// 校验timeStamp的url
	private static List<String> timeStampList;
	// app类型url
	private static List<String> AppSUrlList;
	private static List<String> AppYUrlList;
	// 平台类型url
	private static List<String> platformUrlList;
	// 门户类型url
	private static List<String> portalSUrlList;
	private static List<String> portalYUrlList;
	
	private static List<String> goList = new ArrayList<String>();
	// 请求提交方式
	private final static String METHOD_GET = "GET";
	private final static String METHOD_POST = "POST";
	// 前端传过来的的签名数据的参数名
	private final static String VERIFY_PARAME = "h5SslSignData";
	// 请求提交方式的确定
	public final static String REQUEST_METHOD_TYPE = "application/json";
	// 请求提交方式的确定
	//ajax 方式提交
	public final static String REQUEST_HEADER_AJAX = "XMLHttpRequest";
	// 过滤敏感字符需要排除的参数名称
	public static List<String> PASS_KEYS = new ArrayList<String>();
	// 排除带后缀的参数
	public final static String PASS_KEYS_SUFFIX = "IMG";


	static {
		

		// 初始化静态参数
		PASS_KEYS.add("token");
		PASS_KEYS.add(VERIFY_PARAME);
		PASS_KEYS.add("fileContent");
		PASS_KEYS.add("doc");
		PASS_KEYS.add("createUrl");
		PASS_KEYS.add("imageOR");
		PASS_KEYS.add("imgLists");
		PASS_KEYS.add("base64");
		PASS_KEYS.add("image");// 不拦截图片参数
	}

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		// 拦截路径被修改后使用这个获取url 不带工程名的 request.getRequestURI() 带工程名不可取
		String url = request.getServletPath() +"  "+ request.getPathInfo();
		String uri = request.getRequestURI();
		//1. 放过不需要验证的url放行
		for (String path : list) {
			if (uri.contains(path)) {
				// 如果包含 就放过不验证
				log.info(uri + "  放过");
				return true;
			}
		}
		log.info(uri + " 开始验证");
		request.setCharacterEncoding("UTF-8");
		HttpSession session = request.getSession();
		// 拦截敏感字符 没有提交类型 不做验证
		String contenType = request.getHeader("Content-Type");
		String acceptType = request.getHeader("Accept");
		String headerAjax = request.getHeader("X-Requested-With");

		Map<String, String> dataMap = new HashMap<String, String>();
		BaseVO vo = new BaseVO();
		// 获取所有的参数和值,过程中过滤敏感字符
		boolean b = true;
		// 区分ajax的提交类型 解析json数组情况的内容
		if (contenType != null && contenType.length() > 0 && contenType.contains(REQUEST_METHOD_TYPE)) {
			String requestBody = this.getRequestPayload(request);
			// 1验证敏感词
			b = setDataMap(requestBody, dataMap);
		} else {
			//form 或者get 提交类型数据
			Map<String, String[]> map = request.getParameterMap();
			String queryString = request.getQueryString();
			log.info("获取: "+queryString);
			//1验证敏感词
			b = this.getParameterMap(map, dataMap);
		}
		
		// 处理敏感词的过滤结果
		if (!b) {
			response.setHeader("Content-type", "text/html;charset=UTF-8");
			response.setCharacterEncoding("UTF-8");
			// 如果包含,则是ajax提交,否则是form提交
			if (acceptType.contains(REQUEST_METHOD_TYPE)) {
				Map<String, Object> resultMap = new HashMap<String, Object>();
				resultMap.put("code", "sensitiveError");
				resultMap.put("msg", "操作失败,您输入的内容含有非法字符请检查");
				response.getWriter().println(JSON.toJSONString(resultMap));
			} else {
				response.getWriter().println(this.goBackHtml(request.getContextPath()));
			}
			log.error("操作失败,您输入的内容含有非法字符请检查......");
			return false;
		}else {
			//2验证是否登录
			String channelType = dataMap.get("channelType");
			String token = dataMap.get("token");
			if(!isLogin(channelType,token, request,uri)) {
				//request.getRequestDispatcher("../web/login").forward(request, response);
				return false;
			}
			
			//3验证是否重复提交
			String timeStamp = dataMap.get("timeStamp");
			timeStamp = AESUtil.decrypt(timeStamp);
			for (String path : timeStampList) { 
				if (uri.contains(path)) {// 具备验证timeStamp资格
					log.info("uri: "+uri  +"对比  path: "+path);
					if (!checkSubmit(timeStamp, request, uri)) { // 验证
						log.info("timeStamp 验证失败(请检查是否重复或为空)");
						return false;
					}
				}
			}
			
		}

		// 如果没有参数 直接放过
		if (dataMap == null || dataMap.size() == 0) {
			return true;
		}
		// 开始解析自定义注解
		if (handler instanceof HandlerMethod) {
			Method method = ((HandlerMethod) handler).getMethod();
			// 验签的注解
			log.info("开始验签......");
			if(!verifySign(method,dataMap)) {
				return false;
			}
			
		}  
		return super.preHandle(request, response, handler);
	}
	
	/**
	 * 验证签名
	 * @param method
	 * @param dataMap
	 * @return
	 */
	private Boolean verifySign(Method method,Map<String, String> dataMap) {
		VerifySign verifySign = method.getAnnotation(VerifySign.class);
		if (verifySign != null) {
			String[] verifyFields = verifySign.verifyFields();
			StringBuffer sb = new StringBuffer();
			for (String field : verifyFields) {
				sb.append(dataMap.get(field) == null ? "" : dataMap.get(field));
			}
			// 验签开始
			if (!SignVerifyUtil.verifyFields(sb.toString(), dataMap.get(VERIFY_PARAME))) {
				log.error("验签失败......");
				return false;
			}else {
				log.info("验签成功....");
			}
		}
		return true;
	}
	
	/**
	 * 重复提交校验  
	 * 	1 判断session有没有,没有也是正确 ,设置成前台 ;
	 * 	2 不相等,设置成前台时间.
	 * 	3 如果前台没有,程序终止;
	 * @param timeStamp
	 * @param request
	 * @return
	 */
	private Boolean checkSubmit(String timeStamp,HttpServletRequest request,String methodName){
		Boolean ret = false;
		if (timeStamp != null) {
			String timeStampSession = (String) request.getSession().getAttribute(methodName);
			if (timeStampSession == null) {
				ret = true;
			} else if (!timeStampSession.equals(timeStamp)) {
				ret = true;
			}
			if ( ret ){
				request.getSession().setAttribute(methodName, timeStamp);
			}
		}else {
			log.info("timeStamp 为空");
		}
		return ret;
	}
	
	/**
	 * 验证用户是否登录,根据channelType区分平台,门户,App
	 * @param 
	 * @return
	 * @throws UnsupportedEncodingException 
	 */
	private Boolean isLogin(String channelType, String token, HttpServletRequest request, String uri)
			throws UnsupportedEncodingException {
		boolean flag = false;
			log.info("进入登录验证的uri  :"+uri);
			if (ChannelTypeEnum.APP.getCode().equals(channelType) || ChannelTypeEnum.APP.getCode().equals(AESUtil.decrypt(channelType)) ) {
				// 手机端的交互 验证token有效期
				Jedis jedis = jedisPool.getResource();
				// 判断token超时时间
				String TokenUser = jedis.get("TokenUser" + token);

				User userJson = JSONObject.parseObject(TokenUser, User.class);
				if (!StringUtil.isBlank(TokenUser)) {
					jedis.expire("TokenUser" + token, 1800);
				} else {
					log.info("根据token获取Redis为空,请登录");
					flag = false;
					return flag;
				}
				// 获取用户级别(1用户2.运营商3平台)
				String userLevel = userJson.getUserLevel();
				if ("1".equals(userLevel)) { // 用户菜单权限
					for (String path : AppYUrlList) {
						if (uri.contains(path)) {
							flag = true;
						}
					}
				} else if ("2".equals(userLevel)) { // 商户菜单权限
					for (String path : AppSUrlList) {
						if (uri.contains(path)) {
							flag = true;
						}
					}
				}
			} else {
				// 平台 和 门户展示
				User user = (User) request.getSession().getAttribute("user");
				if (user == null) {
					flag = false;
					log.info("验证是否登录菜单权限返回值:   "+flag);
					return flag;
				}
				// 获取用户级别(1用户2.运营商3平台)
				String userLevel = user.getUserLevel();
				if ("1".equals(userLevel)) { // 用户菜单权限
					for (String path : portalYUrlList) {
						if (uri.contains(path)) {
							log.info("用户进入 uri: "+uri  +"对比  path: "+path);
							flag = true;
						}
					}
				} else if ("2".equals(userLevel)) {
					for (String path : portalSUrlList) {// 商户菜单权限
						if (uri.contains(path)) {
							log.info("商户进入 uri: "+uri  +"对比  path: "+path);
							flag = true;
						}
					}
				} else if ("3".equals(userLevel)) {
					for (String path : platformUrlList) {// 平台菜单权限
						if (uri.contains(path)) {
							log.info("平台进入 uri: "+uri  +"对比  path: "+path);
							flag = true;
						}
					}
				}

			}
			log.info("验证是否登录菜单权限返回值:   "+flag);
		return flag;
	}

	// 敏感词判断 inputString要验证的字段,str该字段值
	private Boolean sensitiveValidate(String inputString) {
		if (inputString == null) {
			return false;
		}
		// 从配置文件读取敏感词字符串并转为数组
		String sensitive = WebConfigUtil.getValue("sensitive").toLowerCase();
		String[] sensitiveArrays = sensitive.split(",");
		inputString = inputString.toLowerCase();
		// 判断入参字段是否含有敏感词数组中的敏感词
		for (int i = 0; i < sensitiveArrays.length; i++) {
			if (inputString.trim().contains(sensitiveArrays[i].trim())) {
				return true;
			}
		}
		return false;
	}

	// 直接返回上一页的数据
	public String goBackHtml(String path) throws IOException {
		StringBuffer sbHtml = new StringBuffer();
		sbHtml.append(
				"<!doctype html><html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">");
		sbHtml.append("<title></title><link href=\"" + path + "/static/pop/pop.css\" rel=\"stylesheet\"></head><body>"
				+ "<script src=\"" + path + "/static/js/jquery-1.9.1.min.js\"></script>"
				+ "<script type=\"text/javascript\" src=\"" + path + "/static/pop/pop.js\"></script>"
				+ "<script>pop('操作失败,您输入的内容含有非法字符请检查');</script></body></html>");
		return sbHtml.toString();
	}

	// 获取ajax中post提交时contentType: "application/json; charset=utf-8"的数据
	private String getRequestPayload(HttpServletRequest req) throws IOException {
		req.setCharacterEncoding("UTF-8");
		StringBuilder sb = new StringBuilder();
		BufferedReader reader = req.getReader();
		char[] buff = new char[1024];
		int len;
		while ((len = reader.read(buff)) != -1) {
			sb.append(buff, 0, len);
		}
		return sb.toString();
	}

	// 递归查询的函数 带返回值 终止
	public boolean setDataMap(String jsonString, Map<String, String> dataMap) {
		if (jsonString == null) {
			return true;
		}
		boolean b = true;
		Map<String, Object> map = JSON.parseObject(jsonString);
		if(map==null) {
			return b;
		}
		// 循环map
		outer: for (Map.Entry<String, Object> entry : map.entrySet()) {
			Object obj = entry.getValue();
			// 排除不需要过滤的参数名
			if (this.passKey(PASS_KEYS, entry.getKey())) {
				dataMap.put(entry.getKey(), obj == null ? "" : obj.toString());
				continue;
			}
			if (obj instanceof JSONObject) {
				// 处理单一对象
				b = setDataMap(obj == null ? "{}" : obj.toString());
				if (!b) {
					break outer;
				}
			} else if (obj instanceof JSONArray) {
				// 处理list 数组对象
				List<Object> list = JSONArray.parseArray(obj == null ? "{}" : obj.toString());
				for (Object json : list) {
					b = setDataMap(json.toString());
					if (!b) {
						break outer;
					}
				}
			} else {
				log.info("解密参数:"+entry.getKey()+"   值:  "+obj);
				// 基本数据类型
				if (this.sensitiveValidate(this.getValue(obj == null ? "" : obj.toString()))) {
					b = false;
					break outer;
				} else {
					dataMap.put(entry.getKey(), obj == null ? "" : obj.toString());
				}
			}
		}
		return b;
	}

	// 递归查询的函数 带返回值 终止
	public boolean setDataMap(String jsonString) {
		if (jsonString == null) {
			return true;
		}
		boolean b = true;
		Map<String, Object> map = JSON.parseObject(jsonString);
		// 循环map
		outer: for (Map.Entry<String, Object> entry : map.entrySet()) {
			// 排除不需要过滤的参数名
			if (this.passKey(PASS_KEYS, entry.getKey())) {
				continue;
			}
			Object obj = entry.getValue();
			if (obj instanceof JSONObject) {
				// 处理单一对象
				b = setDataMap(obj == null ? "{}" : obj.toString());
				if (!b) {
					break outer;
				}
			} else if (obj instanceof JSONArray) {
				// 处理list 数组对象
				List<Object> list = JSONArray.parseArray(obj == null ? "{}" : obj.toString());
				for (Object json : list) {
					b = setDataMap(json.toString());
					if (!b) {
						break outer;
					}
				}
			} else {
				// 基本数据类型
				if (this.sensitiveValidate(this.getValue(obj == null ? "" : obj.toString()))) {
					b = false;
					break outer;
				}
			}
		}
		return b;
	}

	// 获取解密后的信息
	private String getValue(String value) {
		String temp = null;
		try {
			if (value != null && value.length() > 31) { // 排除未加密的字段
				temp = value;
				value = AESUtil.decrypt(value); // 解密字段值
			}
		} catch (Exception e) {
			log.info("解密失败 ,可以忽略的异常", e);
		}
		// 没有加密的参数重新赋值
		return value == null ? temp : value;
	}

	// 排除不过滤的参数名 key
	private boolean passKey(List<String> keys, String key) {
		if (keys == null || keys.size() == 0 || key == null || key.length() == 0) {
			return true;
		}
		return keys.contains(key) || key.endsWith(PASS_KEYS_SUFFIX);
	}

	// 验证是否有敏感词
	private boolean getParameterMap(Map<String, String[]> map, Map<String, String> dataMap) {
		String[] tmp = null;
		for (String key : map.keySet()) {
			tmp = map.get(key);
			// 排除不需要过滤的参数名
			if (this.passKey(PASS_KEYS, key)) {
				dataMap.put(key, tmp == null ? "" : tmp[0]);
				continue;
			}
			// 验签排除list类型的key值数据
			if (key == null || key.endsWith("]")) {
				continue;
			}
			log.info("解密字段 :  "+key  +"   值:  "+ tmp);
			for (String value : tmp) {
				value = this.getValue(value);
				// 敏感词校验
				if (sensitiveValidate(value)) {
					return false;
				} else {
					// 验签排除 数组的数据
					if (map.get(key) != null && map.get(key).length == 1) {
						dataMap.put(key, tmp[0]);
					}
				}
			}
		}
		return true;
	}

	/**
	 * 验证session存在的token和页面提交的token 值 是否相等
	 * 
	 * 
	 * @param request
	 * @return true:验证通过;false:验证不通过;
	 */
	private boolean isRepeatSubmit(HttpServletRequest request) {
		String serverToken = (String) request.getSession(false).getAttribute("token");
		String clinetToken = request.getParameter("token");
		if (serverToken == null || clinetToken == null) {
			return true;
		}
		if (!serverToken.equals(clinetToken)) {
			return true;
		}
		return false;
	}

	public static List<String> getList() {
		return list;
	}

	public static void setList(List<String> list) {
		SystemHandlerInterceptor.list = list;
	}

	public static List<String> getTimeStampList() {
		return timeStampList;
	}

	public static void setTimeStampList(List<String> timeStampList) {
		SystemHandlerInterceptor.timeStampList = timeStampList;
	}

	public static List<String> getAppSUrlList() {
		return AppSUrlList;
	}

	public static void setAppSUrlList(List<String> appSUrlList) {
		AppSUrlList = appSUrlList;
	}

	public static List<String> getAppYUrlList() {
		return AppYUrlList;
	}

	public static void setAppYUrlList(List<String> appYUrlList) {
		AppYUrlList = appYUrlList;
	}

	public static List<String> getPlatformUrlList() {
		return platformUrlList;
	}

	public static void setPlatformUrlList(List<String> platformUrlList) {
		SystemHandlerInterceptor.platformUrlList = platformUrlList;
	}

	public static List<String> getPortalSUrlList() {
		return portalSUrlList;
	}

	public static void setPortalSUrlList(List<String> portalSUrlList) {
		SystemHandlerInterceptor.portalSUrlList = portalSUrlList;
	}

	public static List<String> getPortalYUrlList() {
		return portalYUrlList;
	}

	public static void setPortalYUrlList(List<String> portalYUrlList) {
		SystemHandlerInterceptor.portalYUrlList = portalYUrlList;
	}



}

2. 验签注解
package com.sys.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**

  • 自定义验签注解
    */

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface VerifySign {
//验签字段集合
String[] verifyFields() default{};
//签名字段集合
String[] signFields() default {“rtnCode”,“sslUuid”};
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值