xiaoyong931011
2021-07-21 f79dd632f83167b3cd5ad01e2f7c494b92c834d3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
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<String> nonceList = new ArrayList<>();
            nonceList.add(nonce);
            redisUtil.setex(nonceKey,JSONUtil.toJsonStr(nonceList),timeLimit);
        } else {
            List<String> 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();
    }
}