Quellcode durchsuchen

Revert "token权限控制移至gateway"

This reverts commit 39f34bed
Aslee vor 3 Jahren
Ursprung
Commit
ec3c43ef8d
1 geänderte Dateien mit 123 neuen und 0 gelöschten Zeilen
  1. 123 0
      src/main/java/com/caimei365/user/config/TokenFilter.java

+ 123 - 0
src/main/java/com/caimei365/user/config/TokenFilter.java

@@ -0,0 +1,123 @@
+package com.caimei365.user.config;
+
+import com.alibaba.fastjson.JSONObject;
+import com.caimei365.user.components.RedisService;
+import com.caimei365.user.utils.JwtUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.buffer.DataBuffer;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+import org.springframework.stereotype.Component;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.server.WebFilter;
+import org.springframework.web.server.WebFilterChain;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+/**
+ * JWT Token
+ *
+ * 续签逻辑:
+ * 登录成功后,用户在未过期时间内继续操作,续签token。
+ * 登录成功后,空闲超过过期时间,返回token已失效,重新登录。
+ * 实现逻辑:
+ * 1.登录成功后将token存储到redis里面(这时候k、v值一样都为token),并设置过期时间为token过期时间
+ * 2.当用户请求时token值还未过期,则重新设置redis里token的过期时间。
+ * 3.当用户请求时token值已过期,但redis中还在,则JWT重新生成token并覆盖v值(这时候k、v值不一样了),然后设置redis过期时间。
+ * 4.当用户请求时token值已过期,并且redis中也不存在,则用户空闲超时,返回token已失效,重新登录。
+ *
+ * @author : Charles
+ * @date : 2021/3/30
+ */
+@Slf4j
+@Component
+public class TokenFilter implements WebFilter {
+
+    private static final String AUTH = "X-Token";
+    /**
+     * 需要权限认证的接口路径
+     */
+    private static final String[] PERMISSION_URLS = new String[]{
+        "/user/club/info/update",
+        "/user/shop/info/update"
+    };
+    private RedisService redisService;
+    @Autowired
+    public void setRedisService(RedisService redisService) {
+        this.redisService = redisService;
+    }
+
+    @Override
+    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
+        ServerHttpRequest request = exchange.getRequest();
+        ServerHttpResponse response = exchange.getResponse();
+
+        HttpHeaders header = request.getHeaders();
+        String token = header.getFirst(AUTH);
+        String url = request.getURI().getPath();
+
+        if (StringUtils.isBlank(token) && Arrays.asList(PERMISSION_URLS).contains(url)) {
+            log.error("未经授权,Token为空!");
+            return tokenErrorResponse(response, "未经授权,Token为空!");
+        }
+
+        if (StringUtils.isNotBlank(token)) {
+            String cacheToken = (String) redisService.get(token);
+            // token续签
+            if (StringUtils.isNotBlank(cacheToken) && !"null".equals(cacheToken) && JwtUtil.isVerify(cacheToken)) {
+                int userId = JwtUtil.parseTokenUid(cacheToken);
+                log.debug("Token续签,UserId:"+userId+",Token:"+token);
+                // 再次校验token有效性
+                if (!JwtUtil.isVerify(cacheToken)) {
+                    // 生成token
+                    String newToken = JwtUtil.createToken(userId);
+                    // 将token存入redis,并设置超时时间(秒)
+                    redisService.set(token, newToken, JwtUtil.getExpireTime());
+                } else {
+                    // 重新设置超时时间(秒)
+                    redisService.expire(token, JwtUtil.getExpireTime());
+                }
+            } else {
+                // 需要验证的路径
+                if(Arrays.asList(PERMISSION_URLS).contains(url)) {
+                    // Token失效
+                    log.error("Token失效,token:"+token+",cacheToken:"+cacheToken);
+                    return tokenErrorResponse(response, "Token失效,请重新登录!");
+                }
+            }
+        }
+        //            //TODO 将用户信息存放在请求header中传递给下游业务
+        //            ServerHttpRequest.Builder mutate = request.mutate();
+        //            mutate.header("demo-user-name", username);
+        //            ServerHttpRequest buildReuqest = mutate.build();
+        //
+        //            //todo 如果响应中需要放数据,也可以放在response的header中
+        //            response.setStatusCode(HttpStatus.OK);
+        //            response.getHeaders().add("demo-user-name",username);
+        //            return chain.filter(exchange.mutate()
+        //                    .request(buildReuqest)
+        //                    .response(response)
+        //                    .build());
+        return chain.filter(exchange);
+    }
+
+    private Mono<Void> tokenErrorResponse(ServerHttpResponse response, String responseMsg){
+        response.setStatusCode(HttpStatus.OK);
+        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
+        JSONObject res = new JSONObject();
+        res.put("code", -99);
+        res.put("msg", responseMsg);
+        byte[] responseByte = res.toJSONString().getBytes(StandardCharsets.UTF_8);
+        DataBuffer buffer = response.bufferFactory().wrap(responseByte);
+        return response.writeWith(Flux.just(buffer));
+    }
+
+
+}