package com.xzx.gc.interceptor; import cn.hutool.crypto.SecureUtil; import cn.hutool.json.JSONUtil; import com.xzx.gc.common.annotations.PassToken; import com.xzx.gc.common.constant.Constants; import com.xzx.gc.common.exception.RestException; import com.xzx.gc.common.utils.*; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; /** * token验证拦截器 * * @author zan.zhong * @date 2018-07-08 20:41 */ @Slf4j @Component public class AuthInterceptor implements HandlerInterceptor { //接口超时时间60s private static final int timeLimit = 60; @Autowired private TokenUtil tokenUtil; @Autowired private BusinessUtil businessUtil; @Autowired private RedisUtil redisUtil; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse httpServletResponse, Object object) throws Exception { log.debug("进行通用拦截器:{}",request.getRequestURI()); /**********请求参数***********************/ String token = request.getHeader("token"); String timestamp = request.getHeader("timestamp"); String nonce = request.getHeader("nonce"); String sign = request.getHeader("sign"); String version = request.getHeader("version"); String mobilePhone = request.getHeader("mobilePhone"); String userId = request.getHeader("userId"); String clientType = request.getHeader("clientType"); String authKey = request.getHeader("authKey"); //ip地址 String ip=IpUtils.getIpAddr(request); LogUtils.setTraceId(LogUtils.TRACE_USER_ID,userId==null?"匿名":userId); /********请求参数END***********************/ /********************忽略的请求********************/ if(SpringUtil.isDev()&&"true".equals(request.getHeader("swagger"))){ return true; } // 如果不是映射到方法直接通过或者是否有passtoken注释,有则跳过认证 if (!(object instanceof HandlerMethod)) { return true; } HandlerMethod handlerMethod = (HandlerMethod) object; Method method = handlerMethod.getMethod(); if (method.isAnnotationPresent(PassToken.class)) { PassToken passToken = method.getAnnotation(PassToken.class); if (passToken.required()) { return true; } } /**************请求头参数非空验证********************/ validHead(ip,token, timestamp, nonce, sign, version, mobilePhone, userId, clientType,authKey); /***请求时间验证**************/ if (System.currentTimeMillis() - Long.parseLong(timestamp) > (timeLimit * 1000)) { throw new RestException(-1, "网络中断,请重新刷新页面"); } /***********签名验证*********************/ validSign(ip,token, timestamp, nonce, sign, clientType,version,authKey); /*********************重复请求验证************************/ validNonce(ip,nonce, version, mobilePhone, userId); /**token验证*/ validToken(token, version, mobilePhone, userId); /*********传递信息**************/ request.setAttribute("userId",userId); return true; } private void validNonce(String ip,String nonce, String version, String mobilePhone, String userId) { String nonceKey=null; nonceKey = Constants.REDIS_USER_KEY + "signNonce:"+userId; String list = redisUtil.get(nonceKey); if (StringUtils.isBlank(list)) { List nonceList = new ArrayList<>(); nonceList.add(nonce); redisUtil.setex(nonceKey,JSONUtil.toJsonStr(nonceList),timeLimit); } else { List objects = JSONUtil.parseArray(list).toList(String.class); if (!objects.contains(nonce)) { objects.add(nonce); redisUtil.setex(nonceKey,JSONUtil.toJsonStr(objects),timeLimit); } else { LogUtils.writeIp(ip,"重复的请求"); throw new RestException(-1,"您操作过快,请稍后再试"); } } } private void validSign(String ip,String token, String timestamp, String nonce, String sign, String clientType,String version,String authKey) { String newTokenString=""; String newSign=""; if(businessUtil.isAuth(version)){ newTokenString = token + timestamp + nonce + "v1.1" + clientType +authKey+ Constants.SIGN_SECRET_NEW; newSign=sign; }else { newTokenString = token + timestamp + nonce + "v1.1" + clientType + Constants.SIGN_SECRET; newSign = SecureUtil.md5(newTokenString).toUpperCase(); } if (!newSign.equals(sign)) { LogUtils.writeIp(ip,"签名不一致"); throw new RestException(-2,"签名不一致"); } } private void validHead(String ip,String token, String timestamp, String nonce, String sign, String version, String mobilePhone, String userId, String clientType,String authKey) { if (StringUtils.isEmpty(token)) { LogUtils.writeIp(ip,"请求头缺失token参数"); throw new RestException(-2, "请求头参数不正确"); }else if( StringUtils.isEmpty(timestamp)){ LogUtils.writeIp(ip,"请求头缺失timestamp参数"); throw new RestException(-2, "请求头参数不正确"); }else if(StringUtils.isEmpty(nonce)){ LogUtils.writeIp(ip,"请求头缺失nonce参数"); throw new RestException(-2, "请求头参数不正确"); }else if(StringUtils.isEmpty(sign) ){ LogUtils.writeIp(ip,"请求头缺失sign参数"); throw new RestException(-2, "请求头参数不正确"); }else if(StringUtils.isEmpty(version) ){ LogUtils.writeIp(ip,"请求头缺失version参数"); throw new RestException(-2, "请求头参数不正确"); }else if(StringUtils.isEmpty(clientType)){ LogUtils.writeIp(ip,"请求头缺失clientType参数"); throw new RestException(-2, "请求头参数不正确"); }else if(StringUtils.isBlank(userId)){ LogUtils.writeIp(ip,"请求头缺失userId参数"); throw new RestException(-2,"请求头参数不正确"); }else if (businessUtil.isAuth(version)) { if(StringUtils.isBlank(authKey)){ LogUtils.writeIp(ip,"请求头缺失authKey参数"); throw new RestException(-2,"请求头参数不正确"); } } } private void validToken(String token, String version, String mobilePhone, String userId) { //验证token是否过期 if (tokenUtil.isExpire(userId)) { throw new RestException(-2,"您的登录已经过期,请重新登录"); } //验证token正确性 if(tokenUtil.verifier(token, userId)==-2){ if(!SpringUtil.isDev()) throw new RestException(-2, "您的登录已经过期,请重新登录"); } //更新token有效时间 tokenUtil.updateTokenExpire(userId); } @Override public void postHandle(HttpServletRequest request, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { // //添加版本头用于更新 // Object versionServiceImpl = SpringUtil.getBean("versionServiceImpl"); // VersionInfo versionInfo=ReflectUtil.invoke(versionServiceImpl, "find"); // if(versionInfo!=null){ // httpServletResponse.addHeader("updateFlag",Convert.toStr(versionInfo.getUpdateFlag())); // httpServletResponse.addHeader("forceUpdateFlag",Convert.toStr(versionInfo.getForceUpdateFlag())); // httpServletResponse.addHeader("apkVersion",versionInfo.getApkMd5()); // } } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { LogUtils.clearTraceId(); } }