peter
2026-01-11 24182d305d731e58bd1a57e00466f42ba3a44a9e
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
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
package com.nq.common.interceptor;
 
 
import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import com.nq.annotation.SameUrlData;
import com.nq.common.ServerResponse;
import com.nq.pojo.User;
import com.nq.utils.PropertiesUtil;
import com.nq.utils.redis.JsonUtil;
import com.nq.utils.redis.RedisShardedPoolUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.lang.Nullable;
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.io.IOException;
import java.io.PrintWriter;
import java.lang.annotation.Annotation;
import java.util.Map;
import java.util.concurrent.TimeUnit;
 
@Component
public class ApiUserAuthorityInterceptor implements HandlerInterceptor {
    private static final Logger log = LoggerFactory.getLogger(ApiUserAuthorityInterceptor.class);
 
 
    private RedisTemplate<String,String> redisTemplate;
 
    public ApiUserAuthorityInterceptor(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }
 
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) throws Exception {
//        httpServletResponse.setHeader("Access-Control-Allow-Origin",httpServletRequest.getHeader("origin"));
//        //该字段可选,是个布尔值,表示是否可以携带cookie
//        httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
//        httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT,PATCH, DELETE, OPTIONS");
//        httpServletResponse.setHeader("Access-Control-Allow-Headers", "*");
//        httpServletResponse.setHeader("Access-Control-Allow-Headers", "usertoken");
        if (HttpMethod.OPTIONS.toString().equals(httpServletRequest.getMethod())){
            return  true;
        }
 
        String url = httpServletRequest.getRequestURI();
        log.info("拦截的url是{}",url);
        if ("/user/upload.do".equals(url)) {
            return true;
        }
        if ("/user/pay.do".equals(url)) {
            return true;
        }
        if ("/user/newStockList.do".equals(url)) {
            return true;
        }
        if ("/user/newStockBuy.do".equals(url)) {
            return true;
        }
        if ("/user/buchahbds.do".equals(url)) {
            return true;
        }
        if ("/user/viewAgreementPdf.do".equals(url)) {
            // PDF查看需要验证用户,允许通过cookie或header的token访问
            User currentUser = getCurrentUser(httpServletRequest);
            if (currentUser == null) {
                // 没有有效token,返回错误
                httpServletResponse.setCharacterEncoding("UTF-8");
                httpServletResponse.setContentType("application/json;charset=UTF-8");
                PrintWriter writer = httpServletResponse.getWriter();
                Map map = Maps.newHashMap();
                map.put("success", Boolean.valueOf(false));
                map.put("msg", "請先登錄,無權限訪問user");
                writer.print(JsonUtil.obj2String(map));
                writer.flush();
                writer.close();
                return false;
            }
            return true; // 已登录,允许访问
        }
        User currentUser = getCurrentUser(httpServletRequest);
        if (null == currentUser) {
//            httpServletResponse.reset();
            httpServletResponse.setCharacterEncoding("UTF-8");
            httpServletResponse.setContentType("application/json;charset=UTF-8");
            PrintWriter writer = httpServletResponse.getWriter();
            Map map = Maps.newHashMap();
            map.put("success", Boolean.valueOf(false));
            map.put("msg", "請先登錄,無權限訪問user");
            writer.print(JsonUtil.obj2String(map));
            writer.flush();
            writer.close();
            return false;
        }
        String uri = httpServletRequest.getRequestURI();
 
 
        //验证重复点击与接口权限等
        Boolean checkFlag = checkUri(httpServletResponse, handler, uri,currentUser);
        if (!checkFlag) {
            return Boolean.FALSE;
        }
        //判断请求头
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler, ModelAndView modelAndView) throws Exception {
    }
 
    /**
     * token验证
     *
     * @param response 返回
     * @param handler  请求头
     * @return R 的统一返回,并拦截
     * @throws Exception 异常情况,则为服务异常
     */
    private Boolean checkUri(HttpServletResponse response, Object handler, String uri,User user) throws Exception {
        //判断连续请求的情况
        if (handler instanceof HandlerMethod) {
            SameUrlData tokenTypeAnnotation = findAnnotation((HandlerMethod) handler, SameUrlData.class);
            //判断是否需要验证连续点击
            if (tokenTypeAnnotation != null && redisTemplate.hasKey(user.getId() + uri)) {
                return responseWrite(response, "請勿頻繁點擊");
            } else {
                //将接口+用户信息存储到缓存中。进行重复点击校验
                redisTemplate.opsForValue().set(user.getId()+ uri, "", 30, TimeUnit.SECONDS);
            }
        }
        return true;
    }
 
    private Boolean responseWrite(HttpServletResponse response, String resultMSG) throws Exception {
        //throw new BaseException(resultCode);
//        定义返回类型为JSON
        response.setContentType("application/json;charset=UTF-8");
//        获取PrintWriter
        PrintWriter out = response.getWriter();
        //将异常类型写入
        ServerResponse<Object> byErrorMsg = ServerResponse.createByErrorMsg(resultMSG);
        out.write(JSON.toJSONString(byErrorMsg));
        //输出流
        out.flush();
        //关闭请求
        out.close();
        return true;
    }
 
    /**
     * 请求结束后进行的操作
     *
     * @param request  请求信息
     * @param response 返回信息
     * @param handler  请求头
     * @param ex       异常情况
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable
    Exception ex) {
        String uri = request.getRequestURI();
 
        if (handler instanceof HandlerMethod) {
 
            User currentUser = getCurrentUser(request);
            SameUrlData tokenTypeAnnotation = findAnnotation((HandlerMethod) handler, SameUrlData.class);
            //没有声明需要权限,或者声明不验证权限
            if (tokenTypeAnnotation != null) {
                redisTemplate.delete(currentUser.getId() + uri);
            }
        }
 
    }
 
    /**
     * 获取接口上的注解
     *
     * @param handler        请求方法
     * @param annotationType 想要获取的注解
     * @param <T>            想要获取的注解类型
     * @return 注解
     */
    private <T extends Annotation> T findAnnotation(HandlerMethod handler, Class<T> annotationType) {
        T annotation = handler.getBeanType().getAnnotation(annotationType);
        if (annotation != null) {
            return annotation;
        }
        return handler.getMethodAnnotation(annotationType);
    }
 
    /**
     * 当前用户token鉴权
     *
     * @param request 请求
     * @return 当前用户
     */
 
    public User getCurrentUser(HttpServletRequest request) {
        String property = PropertiesUtil.getProperty("user.cookie.name");
        System.out.println(property);
        String loginToken = request.getHeader(property);
        
        // 如果header中没有token,尝试从cookie获取
        if (loginToken == null) {
            loginToken = getTokenFromCookie(request);
        }
        
        // 如果cookie中也没有token,尝试从URL参数获取(用于iframe等场景)
        if (loginToken == null) {
            loginToken = request.getParameter("token");
        }
        
        if (loginToken == null) {
            System.out.println("loginToken is null");
            return null;
        }
        System.out.println(loginToken);
        String userJson = RedisShardedPoolUtils.get(loginToken);
 
        if (userJson == null||"".equals(userJson)){
            System.out.println("userJson is null");
            return null;
        }
//        System.out.println(userJson);
        return (User) JsonUtil.string2Obj(userJson, User.class);
    }
 
    /**
     * 从Cookie中获取token
     *
     * @param request 请求
     * @return token
     */
    private String getTokenFromCookie(HttpServletRequest request) {
        javax.servlet.http.Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            String cookieName = PropertiesUtil.getProperty("user.cookie.name");
            for (javax.servlet.http.Cookie cookie : cookies) {
                if (cookieName != null && cookieName.equals(cookie.getName())) {
                    return cookie.getValue();
                }
            }
        }
        return null;
    }
}