From 7a35c474d6153189957422264b57df7ce1daed77 Mon Sep 17 00:00:00 2001 From: RuoYi Date: Thu, 29 Jul 2021 14:51:27 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E7=BD=91=E5=85=B3=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E7=A0=81=E5=93=8D=E5=BA=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ruoyi/common/core/constant/CacheConstants.java | 2 +- .../com/ruoyi/common/core/utils/SecurityUtils.java | 10 ++- .../com/ruoyi/common/core/utils/ServletUtils.java | 66 ++++++++++++++++++ .../ruoyi/common/redis/service/RedisService.java | 11 +++ .../common/security/service/TokenService.java | 10 +++ .../java/com/ruoyi/gateway/filter/AuthFilter.java | 79 +++++++++++----------- .../ruoyi/gateway/filter/BlackListUrlFilter.java | 10 +-- .../ruoyi/gateway/filter/ValidateCodeFilter.java | 10 +-- .../gateway/handler/GatewayExceptionHandler.java | 14 +--- .../gateway/handler/SentinelFallbackHandler.java | 10 +-- ruoyi-ui/src/utils/ruoyi.js | 18 ++--- 11 files changed, 153 insertions(+), 87 deletions(-) diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheConstants.java index 8f666dd..c5ccb44 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheConstants.java +++ b/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"; /** * 令牌前缀 diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/SecurityUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/SecurityUtils.java index f2225be..b7b7b66 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/SecurityUtils.java +++ b/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, ""); diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ServletUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ServletUtils.java index 6809f29..51a6141 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ServletUtils.java +++ b/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 + */ + public static Mono webFluxResponseWriter(ServerHttpResponse response, Object value) + { + return webFluxResponseWriter(response, HttpStatus.OK, value, R.FAIL); + } + + /** + * 设置webflux模型响应 + * + * @param response ServerHttpResponse + * @param code 响应状态码 + * @param value 响应内容 + * @return Mono + */ + public static Mono 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 + */ + public static Mono 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 + */ + public static Mono 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)); + } } diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/service/RedisService.java b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/service/RedisService.java index 4bf7f70..dd76297 100644 --- a/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/service/RedisService.java +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/service/RedisService.java @@ -75,6 +75,17 @@ public class RedisService } /** + * 判断 key是否存在 + * + * @param key 键 + * @return true 存在 false不存在 + */ + public Boolean hasKey(String key) + { + return redisTemplate.hasKey(key); + } + + /** * 获得缓存的基本对象。 * * @param key 缓存键值 diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/service/TokenService.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/service/TokenService.java index a4e8428..95dd8a4 100644 --- a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/service/TokenService.java +++ b/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); diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/AuthFilter.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/AuthFilter.java index 3771b46..8517c79 100644 --- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/AuthFilter.java +++ b/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 sops; - + @Autowired private RedisService redisService; @Override public Mono 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 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 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 diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/BlackListUrlFilter.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/BlackListUrlFilter.java index f613dea..9deab70 100644 --- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/BlackListUrlFilter.java +++ b/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 } 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); }; diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/GatewayExceptionHandler.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/GatewayExceptionHandler.java index 0a8e44a..593e7e6 100644 --- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/GatewayExceptionHandler.java +++ b/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); } } \ No newline at end of file diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/SentinelFallbackHandler.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/SentinelFallbackHandler.java index 80c6460..c770a15 100644 --- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/SentinelFallbackHandler.java +++ b/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 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 diff --git a/ruoyi-ui/src/utils/ruoyi.js b/ruoyi-ui/src/utils/ruoyi.js index f60701e..ee01f9b 100644 --- a/ruoyi-ui/src/utils/ruoyi.js +++ b/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 }