david 2 лет назад
Родитель
Сommit
bbc588e891

+ 77 - 22
src/main/java/com/roma/romaapi/interceptor/JWTInterceptor.java

@@ -4,7 +4,11 @@ import com.auth0.jwt.exceptions.AlgorithmMismatchException;
 import com.auth0.jwt.exceptions.SignatureVerificationException;
 import com.auth0.jwt.exceptions.TokenExpiredException;
 import com.auth0.jwt.interfaces.DecodedJWT;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.util.JSONPObject;
 import com.roma.romaapi.utils.JWTUtil;
+import com.roma.romaapi.utils.CustomResponse;
+import jakarta.servlet.http.HttpServletResponse;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.StringRedisTemplate;
@@ -12,6 +16,10 @@ import org.springframework.http.HttpMethod;
 import org.springframework.stereotype.Component;
 import org.springframework.web.servlet.HandlerInterceptor;
 
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
 import static com.roma.romaapi.utils.JWTUtil.REDIS_USER_EXPIRE_TIME;
@@ -22,6 +30,8 @@ import static com.roma.romaapi.utils.JWTUtil.SIGN;
  验证通过就放行
  验证失败就抛出异常 由统一错误处理类承接 并最终给前端返回错误信息
  ***/
+// 特殊错误码: 50000 表示token失效,需要跳转到登录页面  50000-50999 为校验错误信息
+//           51000 表示没有操作权限
 @Slf4j
 @Component
 public class JWTInterceptor implements HandlerInterceptor {
@@ -37,48 +47,93 @@ public class JWTInterceptor implements HandlerInterceptor {
         if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
             return true;
         }
+
+        Map<String, Object> errorMap = new HashMap<>(); // 存放错误信息
         String authorization = request.getHeader("Authorization");
-        if(authorization==null || authorization.equals("")){
-            throw new Exception("Header 未装载 token");
+        if(authorization==null || authorization.length()<8){
+            errorMap.put("sysErrorCode", "50001");
+            errorMap.put("sysErrorMessage", "Header 未装载 token");
+            // 格式化输出内容,并将map转为json字符串
+            String json = new ObjectMapper().writeValueAsString(CustomResponse.formatResponse(errorMap));
+            returnJson(response, json);
+
+            return false;
         }
-        String token = authorization.substring(7);
-        if(token.equals("")){
-            throw new Exception("Header 未装载 token");
+        String token = authorization.substring(7); // 截取token
+        // 从Redis中获取缓存中的token,判断是否过期
+        String redisTokenKey = SIGN + token;
+        String userId = stringRedisTemplate.opsForValue().get(redisTokenKey);
+        if(null == userId || userId.equals("")){
+            errorMap.put("sysErrorCode", "50000");
+            errorMap.put("sysErrorMessage", "token失效或已过期");
+            // 格式化输出内容,并将map转为json字符串
+            String json = new ObjectMapper().writeValueAsString(CustomResponse.formatResponse(errorMap));
+            returnJson(response, json);
+
+            return false;
         }
+
         try {
             // 得到签名实体
             DecodedJWT verify = jwtUtil.verify(token);
             // 得到签名中的登录时间
             String loginTimeFromToken = verify.getClaim("userLoginTime").asString();
             // 续期
-            String userId = stringRedisTemplate.opsForValue().get(SIGN + token);
-            String redisTokenKey = SIGN + token;
             stringRedisTemplate.opsForValue().set(redisTokenKey, userId, 60*30, TimeUnit.SECONDS);
         } catch (SignatureVerificationException e) {
-            System.out.println("token签名错误-----"+e.getMessage());
-            throw new Exception("无效Token签名");
+            errorMap.put("sysErrorCode", "50002");
+            errorMap.put("sysErrorMessage", "无效Token签名");
+            // 格式化输出内容,并将map转为json字符串
+            String json = new ObjectMapper().writeValueAsString(CustomResponse.formatResponse(errorMap));
+            returnJson(response, json);
+
+            return false;
         } catch (TokenExpiredException e) {
             /*若抛出token过期异常,检查redis中的是否存在token以及请求头中的token与redis中的token是否相同
             如果相同,说明用户仍在操作,只是请求头中的token已经过期,此时需要对token进行续期*/
             // 从Redis中获取缓存中的token,判断是否过期
-            String userId = stringRedisTemplate.opsForValue().get(SIGN + token);
-            if(null == userId || userId.equals("")){
-                throw new Exception("拦截器 Original Token 无效或已过期");
-            } else {
-                // 续期
-                String redisTokenKey = SIGN + token;
-                stringRedisTemplate.opsForValue().set(redisTokenKey, userId, 60*30, TimeUnit.SECONDS);
-
-                return true;
-            }
-//            throw new Exception("token过期");
+            // 续期
+            stringRedisTemplate.opsForValue().set(redisTokenKey, userId, 60*30, TimeUnit.SECONDS);
+
+            return true;
+
         } catch (AlgorithmMismatchException e) {
+            errorMap.put("sysErrorCode", "50003");
+            errorMap.put("sysErrorMessage", "token算法不一致");
+            // 格式化输出内容,并将map转为json字符串
+            String json = new ObjectMapper().writeValueAsString(CustomResponse.formatResponse(errorMap));
+            returnJson(response, json);
 
-            throw new Exception("token算法不一致");
+            return false;
         } catch (Exception e) {
-            throw new Exception("token无效:" + e.getMessage());
+            errorMap.put("sysErrorCode", "50004");
+            errorMap.put("sysErrorMessage", "token无效:" + e.getMessage());
+            // 格式化输出内容,并将map转为json字符串
+            String json = new ObjectMapper().writeValueAsString(CustomResponse.formatResponse(errorMap));
+            returnJson(response, json);
+
+            return false;
         }
 
         return true;
     }
+
+    /**
+     * 返回客户端数据
+     */
+    private void returnJson(HttpServletResponse response, String result) throws Exception {
+        PrintWriter writer = null;
+        response.setCharacterEncoding("UTF-8");
+        response.setContentType("text/html; charset=utf-8");
+        try {
+            writer = response.getWriter();
+            writer.print(result);
+
+        } catch (IOException e) {
+        } finally {
+            if (writer != null) {
+                writer.close();
+            }
+        }
+    }
 }

+ 11 - 3
src/main/java/com/roma/romaapi/utils/CustomResponse.java

@@ -4,6 +4,11 @@ import java.util.HashMap;
 import java.util.Map;
 // 相应工具类
 public class CustomResponse {
+
+    // 特殊的三个系统错误字段:
+    // sysErrorCode 错误码
+    // sysErrorMessage 错误消息
+    // sysErrorData 错误数据
     public static <T> Map success(T data) {
         Map<String, Object> result = new HashMap<>();
         result.put("code", "200");
@@ -29,13 +34,16 @@ public class CustomResponse {
         String message = "success";
         boolean isEmpty = data.containsKey("sysErrorCode");
         if(isEmpty) {
-            Object errorCode = data.get("sysErrorCode");
+            // 如果要返回错误提示
+            boolean isEmptyData = data.containsKey("sysErrorData"); // 错误数据
+            Object errorCode = data.get("sysErrorCode"); // 错误码
             Object errorMessage = data.containsKey("sysErrorMessage") ? data.get("sysErrorMessage")
-                    : new String("operation failed!");
+                    : new String("operation failed!"); // 错误提示信息
             result.put("code", errorCode.toString());
             result.put("message", errorMessage.toString());
-            result.put("data", data);
+            result.put("data", !isEmptyData ? data.get("sysErrorData") : new HashMap<>());
         } else {
+            // 返回正确信息
             result.put("code", code);
             result.put("message", message);
             result.put("data", data);

+ 0 - 7
src/main/java/com/roma/romaapi/utils/JWTUtil.java

@@ -71,15 +71,8 @@ public class JWTUtil {
      * 验证token合法性 成功返回token
      */
     public DecodedJWT verify(String token) throws Exception {
-        if(token.equals("")){
-            throw new Exception("token不能为空");
-        }
         // 从Redis中获取缓存中的token,判断是否过期
         String userId = stringRedisTemplate.opsForValue().get(SIGN + token);
-        if(null == userId || userId.equals("")){
-            throw new Exception("Original Token 无效或已过期");
-        }
-
         JWTVerifier build = JWT.require(Algorithm.HMAC256(userId)).build();
 
         return build.verify(token);