Эх сурвалжийг харах

:punch: JWT拦截器的异常处理和缓存

nnkwrik 6 жил өмнө
parent
commit
fae4c21f1e

+ 6 - 0
common/pom.xml

@@ -51,6 +51,12 @@
             <artifactId>spring-cloud-stream-binder-rabbit</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>27.0-jre</version>
+        </dependency>
+
     </dependencies>
 
     <dependencyManagement>

+ 2 - 0
common/src/main/java/io/github/nnkwrik/common/dto/Response.java

@@ -12,6 +12,8 @@ public class Response<T> {
     //auth
     public static final int WRONG_JS_CODE = 3001;
     public static final int CHECK_USER_WITH_SESSION_FAIL = 3002;
+    public static final int TOKEN_IS_EMPTY = 3003;
+    public static final int TOKEN_IS_EXPIRED = 3004;
 
     //goods
     public static final int OPEN_ID_IS_EMPTY = 4001;

+ 24 - 0
common/src/main/java/io/github/nnkwrik/common/exception/GlobalExceptionHandler.java

@@ -0,0 +1,24 @@
+package io.github.nnkwrik.common.exception;
+
+import io.github.nnkwrik.common.dto.Response;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+/**
+ * @author nnkwrik
+ * @date 18/11/24 12:54
+ */
+@ControllerAdvice
+@Slf4j
+public class GlobalExceptionHandler {
+
+    @ResponseBody
+    @ExceptionHandler(JWTException.class)
+    public Object handleJWTException(JWTException e) {
+        log.info("发生JWTException,errno = {},errmsg = {}", e.getErrno(), e.getErrmsg());
+
+        return Response.fail(e.getErrno(), e.getErrmsg());
+    }
+}

+ 24 - 0
common/src/main/java/io/github/nnkwrik/common/exception/JWTException.java

@@ -0,0 +1,24 @@
+package io.github.nnkwrik.common.exception;
+
+import io.github.nnkwrik.common.dto.Response;
+import lombok.Data;
+
+/**
+ * @author nnkwrik
+ * @date 18/11/24 12:44
+ */
+@Data
+public class JWTException extends RuntimeException {
+    public static final int TOKEN_IS_EMPTY = Response.TOKEN_IS_EMPTY;
+    public static final int TOKEN_IS_EXPIRED = Response.TOKEN_IS_EXPIRED;
+
+    private int errno;
+    private String errmsg;
+
+
+    public JWTException(int errno, String errmsg) {
+        this.errno = errno;
+        this.errmsg = errmsg;
+    }
+
+}

+ 27 - 8
common/src/main/java/io/github/nnkwrik/common/token/injection/JWTResolver.java

@@ -1,7 +1,10 @@
 package io.github.nnkwrik.common.token.injection;
 
 import com.auth0.jwt.exceptions.TokenExpiredException;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
 import io.github.nnkwrik.common.dto.JWTUser;
+import io.github.nnkwrik.common.exception.JWTException;
 import io.github.nnkwrik.common.token.TokenSolver;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -12,6 +15,8 @@ import org.springframework.web.context.request.NativeWebRequest;
 import org.springframework.web.method.support.HandlerMethodArgumentResolver;
 import org.springframework.web.method.support.ModelAndViewContainer;
 
+import java.util.concurrent.TimeUnit;
+
 /**
  * @author nnkwrik
  * @date 18/11/24 9:43
@@ -20,6 +25,9 @@ import org.springframework.web.method.support.ModelAndViewContainer;
 @Component
 public class JWTResolver implements HandlerMethodArgumentResolver {
 
+    private static Cache<String, JWTUser> cache =
+            CacheBuilder.newBuilder().maximumSize(10000).expireAfterWrite(3, TimeUnit.MINUTES).build();
+
     @Autowired
     private TokenSolver tokenSolver;
 
@@ -35,19 +43,30 @@ public class JWTResolver implements HandlerMethodArgumentResolver {
                                   NativeWebRequest webRequest,
                                   WebDataBinderFactory binderFactory) {
         String token = webRequest.getHeader("Authorization");
+        JWTUser user = null;
+        boolean isExpired = false;
         if (token == null) {
             log.info("用户的Authorization头为空,无法获取jwt");
-            return null;
+        } else if ((user = cache.getIfPresent(token)) == null) {   //试图从缓存获取
+
+            try {
+                user = tokenSolver.solve(token);
+                cache.put(token, user);
+            } catch (TokenExpiredException e) {
+                log.info("jwt已过期,过期时间:{}", e.getMessage());
+                isExpired = true;
+            } catch (Exception e) {
+                log.info("jwt解析失败");
+            }
         }
-        JWTUser user = null;
-        try {
-            user = tokenSolver.solve(token);
-        } catch (TokenExpiredException e) {
-            log.info("jwt已过期,过期时间:{}", e.getMessage());
-        } catch (Exception e) {
-            log.info("jwt解析失败");
+
+        if (user == null &&
+                parameter.getParameterAnnotation(JWT.class).required()) {
+            if (isExpired) throw new JWTException(JWTException.TOKEN_IS_EXPIRED, "凭证已过期");
+            throw new JWTException(JWTException.TOKEN_IS_EMPTY, "用户的Authorization头错误,无法获取jwt");
         }
         log.info("jwt解析结果为:{}", user);
+
         return user;
     }
 

+ 17 - 0
goods-service/src/main/java/io/github/nnkwrik/goodsservice/controller/TestController.java

@@ -45,6 +45,11 @@ public class TestController {
     }
 
 
+    /**
+     * jwt解析失败时会抛错
+     * @param jwt
+     * @return
+     */
     @GetMapping("/testInjection")
     public JWTUser testInject(@JWT JWTUser jwt) {
 
@@ -52,6 +57,18 @@ public class TestController {
         return jwt;
     }
 
+    /**
+     * jwt解析失败时不会抛错
+     * @param jwt 解析失败时是null
+     * @return
+     */
+    @GetMapping("/testInjection2")
+    public JWTUser testInject2(@JWT(required = false) JWTUser jwt) {
+
+        System.out.println("============" + jwt);
+        return jwt;
+    }
+
     @Autowired
     private TokenSolver tokenSolver;