ソースを参照

统一网关错误码响应

RuoYi 3 年 前
コミット
7a35c474d6

+ 1 - 1
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheConstants.java

@@ -10,7 +10,7 @@ public class CacheConstants
     /**
      * 令牌自定义标识
      */
-    public static final String HEADER = "Authorization";
+    public static final String TOKEN_AUTHENTICATION = "Authorization";
 
     /**
      * 令牌前缀

+ 9 - 1
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/SecurityUtils.java

@@ -42,7 +42,15 @@ public class SecurityUtils
      */
     public static String getToken(HttpServletRequest request)
     {
-        String token = ServletUtils.getRequest().getHeader(CacheConstants.HEADER);
+        String token = request.getHeader(CacheConstants.TOKEN_AUTHENTICATION);
+        return replaceTokenPrefix(token);
+    }
+
+    /**
+     * 替换token前缀
+     */
+    public static String replaceTokenPrefix(String token)
+    {
         if (StringUtils.isNotEmpty(token) && token.startsWith(CacheConstants.TOKEN_PREFIX))
         {
             token = token.replace(CacheConstants.TOKEN_PREFIX, "");

+ 66 - 0
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ServletUtils.java

@@ -10,11 +10,19 @@ import java.util.Map;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
+import org.springframework.core.io.buffer.DataBuffer;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.server.reactive.ServerHttpResponse;
 import org.springframework.web.context.request.RequestAttributes;
 import org.springframework.web.context.request.RequestContextHolder;
 import org.springframework.web.context.request.ServletRequestAttributes;
+import com.alibaba.fastjson.JSONObject;
 import com.ruoyi.common.core.constant.Constants;
+import com.ruoyi.common.core.domain.R;
 import com.ruoyi.common.core.text.Convert;
+import reactor.core.publisher.Mono;
 
 /**
  * 客户端工具类
@@ -213,4 +221,62 @@ public class ServletUtils
             return "";
         }
     }
+
+    /**
+     * 设置webflux模型响应
+     *
+     * @param response ServerHttpResponse
+     * @param value 响应内容
+     * @return Mono<Void>
+     */
+    public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, Object value)
+    {
+        return webFluxResponseWriter(response, HttpStatus.OK, value, R.FAIL);
+    }
+
+    /**
+     * 设置webflux模型响应
+     *
+     * @param response ServerHttpResponse
+     * @param code 响应状态码
+     * @param value 响应内容
+     * @return Mono<Void>
+     */
+    public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, Object value, int code)
+    {
+        return webFluxResponseWriter(response, HttpStatus.OK, value, code);
+    }
+
+    /**
+     * 设置webflux模型响应
+     *
+     * @param response ServerHttpResponse
+     * @param status http状态码
+     * @param code 响应状态码
+     * @param value 响应内容
+     * @return Mono<Void>
+     */
+    public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, HttpStatus status, Object value, int code)
+    {
+        return webFluxResponseWriter(response, MediaType.APPLICATION_JSON_VALUE, status, value, code);
+    }
+
+    /**
+     * 设置webflux模型响应
+     *
+     * @param response ServerHttpResponse
+     * @param contentType content-type
+     * @param status http状态码
+     * @param code 响应状态码
+     * @param value 响应内容
+     * @return Mono<Void>
+     */
+    public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, String contentType, HttpStatus status, Object value, int code)
+    {
+        response.setStatusCode(status);
+        response.getHeaders().add(HttpHeaders.CONTENT_TYPE, contentType);
+        R<?> result = R.fail(code, value.toString());
+        DataBuffer dataBuffer = response.bufferFactory().wrap(JSONObject.toJSONString(result).getBytes());
+        return response.writeWith(Mono.just(dataBuffer));
+    }
 }

+ 11 - 0
ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/service/RedisService.java

@@ -74,6 +74,17 @@ public class RedisService
         return redisTemplate.expire(key, timeout, unit);
     }
 
+    /**
+     * 判断 key是否存在
+     *
+     * @param key 键
+     * @return true 存在 false不存在
+     */
+    public Boolean hasKey(String key)
+    {
+        return redisTemplate.hasKey(key);
+    }
+
     /**
      * 获得缓存的基本对象。
      *

+ 10 - 0
ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/service/TokenService.java

@@ -73,6 +73,16 @@ public class TokenService
     {
         // 获取请求携带的令牌
         String token = SecurityUtils.getToken(request);
+        return getLoginUser(token);
+    }
+
+    /**
+     * 获取用户身份信息
+     *
+     * @return 用户信息
+     */
+    public LoginUser getLoginUser(String token)
+    {
         if (StringUtils.isNotEmpty(token))
         {
             String userKey = getTokenKey(token);

+ 39 - 40
ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/AuthFilter.java

@@ -7,19 +7,15 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.cloud.gateway.filter.GatewayFilterChain;
 import org.springframework.cloud.gateway.filter.GlobalFilter;
 import org.springframework.core.Ordered;
-import org.springframework.core.io.buffer.DataBufferFactory;
 import org.springframework.data.redis.core.ValueOperations;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
 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 com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.ruoyi.common.core.constant.CacheConstants;
 import com.ruoyi.common.core.constant.Constants;
-import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.core.constant.HttpStatus;
+import com.ruoyi.common.core.utils.SecurityUtils;
 import com.ruoyi.common.core.utils.ServletUtils;
 import com.ruoyi.common.core.utils.StringUtils;
 import com.ruoyi.common.redis.service.RedisService;
@@ -35,7 +31,7 @@ import reactor.core.publisher.Mono;
 public class AuthFilter implements GlobalFilter, Ordered
 {
     private static final Logger log = LoggerFactory.getLogger(AuthFilter.class);
-    
+
     private final static long EXPIRE_TIME = Constants.TOKEN_EXPIRE * 60;
 
     // 排除过滤的 uri 地址,nacos自行添加
@@ -44,61 +40,68 @@ public class AuthFilter implements GlobalFilter, Ordered
 
     @Resource(name = "stringRedisTemplate")
     private ValueOperations<String, String> sops;
-    
+
     @Autowired
     private RedisService redisService;
 
     @Override
     public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
     {
-        String url = exchange.getRequest().getURI().getPath();
+        ServerHttpRequest request = exchange.getRequest();
+        ServerHttpRequest.Builder mutate = request.mutate();
+
+        String url = request.getURI().getPath();
         // 跳过不需要验证的路径
         if (StringUtils.matches(url, ignoreWhite.getWhites()))
         {
             return chain.filter(exchange);
         }
-        String token = getToken(exchange.getRequest());
-        if (StringUtils.isBlank(token))
+        String token = getToken(request);
+        if (StringUtils.isEmpty(token))
         {
-            return setUnauthorizedResponse(exchange, "令牌不能为空");
+            return unauthorizedResponse(exchange, "令牌不能为空");
         }
         String userStr = sops.get(getTokenKey(token));
-        if (StringUtils.isNull(userStr))
+        if (StringUtils.isEmpty(userStr))
         {
-            return setUnauthorizedResponse(exchange, "登录状态已过期");
+            return unauthorizedResponse(exchange, "登录状态已过期");
         }
-        JSONObject obj = JSONObject.parseObject(userStr);
-        String userid = obj.getString("userid");
-        String username = obj.getString("username");
-        if (StringUtils.isBlank(userid) || StringUtils.isBlank(username))
+        JSONObject cacheObj = JSONObject.parseObject(userStr);
+        String userid = cacheObj.getString("userid");
+        String username = cacheObj.getString("username");
+        if (StringUtils.isEmpty(userid) || StringUtils.isEmpty(username))
         {
-            return setUnauthorizedResponse(exchange, "令牌验证失败");
+            return unauthorizedResponse(exchange, "令牌验证失败");
         }
-        
+
         // 设置过期时间
         redisService.expire(getTokenKey(token), EXPIRE_TIME);
         // 设置用户信息到请求
-        ServerHttpRequest mutableReq = exchange.getRequest().mutate().header(CacheConstants.DETAILS_USER_ID, userid)
-                .header(CacheConstants.DETAILS_USERNAME, ServletUtils.urlEncode(username)).build();
-        ServerWebExchange mutableExchange = exchange.mutate().request(mutableReq).build();
-
-        return chain.filter(mutableExchange);
+        addHeader(mutate, CacheConstants.DETAILS_USER_ID, userid);
+        addHeader(mutate, CacheConstants.DETAILS_USERNAME, username);
+        return chain.filter(exchange.mutate().request(mutate.build()).build());
     }
 
-    private Mono<Void> setUnauthorizedResponse(ServerWebExchange exchange, String msg)
+    private void addHeader(ServerHttpRequest.Builder mutate, String name, Object value)
     {
-        ServerHttpResponse response = exchange.getResponse();
-        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
-        response.setStatusCode(HttpStatus.OK);
+        if (value == null)
+        {
+            return;
+        }
+        String valueStr = value.toString();
+        String valueEncode = ServletUtils.urlEncode(valueStr);
+        mutate.header(name, valueEncode);
+    }
 
+    private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, String msg)
+    {
         log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath());
-
-        return response.writeWith(Mono.fromSupplier(() -> {
-            DataBufferFactory bufferFactory = response.bufferFactory();
-            return bufferFactory.wrap(JSON.toJSONBytes(R.fail(HttpStatus.UNAUTHORIZED.value(), msg)));
-        }));
+        return ServletUtils.webFluxResponseWriter(exchange.getResponse(), msg, HttpStatus.UNAUTHORIZED);
     }
 
+    /**
+     * 获取缓存key
+     */
     private String getTokenKey(String token)
     {
         return CacheConstants.LOGIN_TOKEN_KEY + token;
@@ -109,12 +112,8 @@ public class AuthFilter implements GlobalFilter, Ordered
      */
     private String getToken(ServerHttpRequest request)
     {
-        String token = request.getHeaders().getFirst(CacheConstants.HEADER);
-        if (StringUtils.isNotEmpty(token) && token.startsWith(CacheConstants.TOKEN_PREFIX))
-        {
-            token = token.replace(CacheConstants.TOKEN_PREFIX, "");
-        }
-        return token;
+        String token = request.getHeaders().getFirst(CacheConstants.TOKEN_AUTHENTICATION);
+        return SecurityUtils.replaceTokenPrefix(token);
     }
 
     @Override

+ 2 - 8
ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/BlackListUrlFilter.java

@@ -5,11 +5,8 @@ import java.util.List;
 import java.util.regex.Pattern;
 import org.springframework.cloud.gateway.filter.GatewayFilter;
 import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
-import org.springframework.http.server.reactive.ServerHttpResponse;
 import org.springframework.stereotype.Component;
-import com.alibaba.fastjson.JSON;
-import com.ruoyi.common.core.web.domain.AjaxResult;
-import reactor.core.publisher.Mono;
+import com.ruoyi.common.core.utils.ServletUtils;
 
 /**
  * 黑名单过滤器
@@ -27,10 +24,7 @@ public class BlackListUrlFilter extends AbstractGatewayFilterFactory<BlackListUr
             String url = exchange.getRequest().getURI().getPath();
             if (config.matchBlacklist(url))
             {
-                ServerHttpResponse response = exchange.getResponse();
-                response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
-                return exchange.getResponse().writeWith(
-                        Mono.just(response.bufferFactory().wrap(JSON.toJSONBytes(AjaxResult.error("请求地址不允许访问")))));
+                return ServletUtils.webFluxResponseWriter(exchange.getResponse(), "请求地址不允许访问");
             }
 
             return chain.filter(exchange);

+ 2 - 8
ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/ValidateCodeFilter.java

@@ -9,16 +9,13 @@ import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFac
 import org.springframework.core.io.buffer.DataBuffer;
 import org.springframework.core.io.buffer.DataBufferUtils;
 import org.springframework.http.server.reactive.ServerHttpRequest;
-import org.springframework.http.server.reactive.ServerHttpResponse;
 import org.springframework.stereotype.Component;
-import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
+import com.ruoyi.common.core.utils.ServletUtils;
 import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.core.web.domain.AjaxResult;
 import com.ruoyi.gateway.config.properties.CaptchaProperties;
 import com.ruoyi.gateway.service.ValidateCodeService;
 import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
 
 /**
  * 验证码过滤器
@@ -60,10 +57,7 @@ public class ValidateCodeFilter extends AbstractGatewayFilterFactory<Object>
             }
             catch (Exception e)
             {
-                ServerHttpResponse response = exchange.getResponse();
-                response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
-                return exchange.getResponse().writeWith(
-                        Mono.just(response.bufferFactory().wrap(JSON.toJSONBytes(AjaxResult.error(e.getMessage())))));
+                return ServletUtils.webFluxResponseWriter(exchange.getResponse(), e.getMessage());
             }
             return chain.filter(exchange);
         };

+ 2 - 12
ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/GatewayExceptionHandler.java

@@ -6,14 +6,10 @@ import org.slf4j.LoggerFactory;
 import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.core.annotation.Order;
-import org.springframework.core.io.buffer.DataBufferFactory;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
 import org.springframework.http.server.reactive.ServerHttpResponse;
 import org.springframework.web.server.ResponseStatusException;
 import org.springframework.web.server.ServerWebExchange;
-import com.alibaba.fastjson.JSON;
-import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.core.utils.ServletUtils;
 import reactor.core.publisher.Mono;
 
 /**
@@ -55,12 +51,6 @@ public class GatewayExceptionHandler implements ErrorWebExceptionHandler
 
         log.error("[网关异常处理]请求路径:{},异常信息:{}", exchange.getRequest().getPath(), ex.getMessage());
 
-        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
-        response.setStatusCode(HttpStatus.OK);
-
-        return response.writeWith(Mono.fromSupplier(() -> {
-            DataBufferFactory bufferFactory = response.bufferFactory();
-            return bufferFactory.wrap(JSON.toJSONBytes(R.fail(msg)));
-        }));
+        return ServletUtils.webFluxResponseWriter(response, msg);
     }
 }

+ 2 - 8
ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/SentinelFallbackHandler.java

@@ -1,10 +1,8 @@
 package com.ruoyi.gateway.handler;
 
-import java.nio.charset.StandardCharsets;
 import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
 import com.alibaba.csp.sentinel.slots.block.BlockException;
-import org.springframework.core.io.buffer.DataBuffer;
-import org.springframework.http.server.reactive.ServerHttpResponse;
+import com.ruoyi.common.core.utils.ServletUtils;
 import org.springframework.web.reactive.function.server.ServerResponse;
 import org.springframework.web.server.ServerWebExchange;
 import org.springframework.web.server.WebExceptionHandler;
@@ -19,11 +17,7 @@ public class SentinelFallbackHandler implements WebExceptionHandler
 {
     private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange)
     {
-        ServerHttpResponse serverHttpResponse = exchange.getResponse();
-        serverHttpResponse.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
-        byte[] datas = "{\"code\":429,\"msg\":\"请求超过最大数,请稍后再试\"}".getBytes(StandardCharsets.UTF_8);
-        DataBuffer buffer = serverHttpResponse.bufferFactory().wrap(datas);
-        return serverHttpResponse.writeWith(Mono.just(buffer));
+        return ServletUtils.webFluxResponseWriter(exchange.getResponse(), "请求超过最大数,请稍后再试");
     }
 
     @Override

+ 9 - 9
ruoyi-ui/src/utils/ruoyi.js

@@ -185,15 +185,15 @@ export function tansParams(params) {
         var part = encodeURIComponent(propName) + "=";
         if (value !== null && typeof(value) !== "undefined") {
             if (typeof value === 'object') {
-				for (const key of Object.keys(value)) {
-					let params = propName + '[' + key + ']';
-					var subPart = encodeURIComponent(params) + "=";
-					result += subPart + encodeURIComponent(value[key]) + "&";
-				}
+                for (const key of Object.keys(value)) {
+                    let params = propName + '[' + key + ']';
+                    var subPart = encodeURIComponent(params) + "=";
+                    result += subPart + encodeURIComponent(value[key]) + "&";
+                }
             } else {
-				result += part + encodeURIComponent(value) + "&";
-            }
-		}
+                result += part + encodeURIComponent(value) + "&";
+           }
+        }
     }
-	return result
+    return result
 }