From d73a975c16b39e51e0d5829e051697671fc014ff Mon Sep 17 00:00:00 2001 From: wxz Date: Wed, 11 Aug 2021 23:39:18 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=9Agateway=E4=B8=AD?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=AF=B7=E6=B1=82url=E7=9A=84=E6=97=A5?= =?UTF-8?q?=E5=BF=97=EF=BC=8C=E5=92=8C=E6=8A=A5=E9=94=99=E7=9A=84=E6=97=A5?= =?UTF-8?q?=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/ExtAppTakeTokenAuthProcessor.java | 6 +- .../filter/CpAuthGatewayFilterFactory.java | 344 ++++++++++-------- 2 files changed, 197 insertions(+), 153 deletions(-) diff --git a/epmet-gateway/src/main/java/com/epmet/auth/ExtAppTakeTokenAuthProcessor.java b/epmet-gateway/src/main/java/com/epmet/auth/ExtAppTakeTokenAuthProcessor.java index 6b527dc074..dcede2b1d0 100644 --- a/epmet-gateway/src/main/java/com/epmet/auth/ExtAppTakeTokenAuthProcessor.java +++ b/epmet-gateway/src/main/java/com/epmet/auth/ExtAppTakeTokenAuthProcessor.java @@ -1,7 +1,6 @@ package com.epmet.auth; import com.epmet.commons.security.jwt.JwtUtils; -import com.epmet.commons.security.sign.openapi.OpenApiSignUtils; import com.epmet.commons.tools.exception.EpmetErrorCode; import com.epmet.commons.tools.exception.RenException; import com.epmet.commons.tools.redis.RedisKeys; @@ -12,7 +11,6 @@ import com.epmet.feign.EpmetCommonServiceOpenFeignClient; import com.epmet.openapi.constant.InClusterHeaderKeys; import com.epmet.openapi.constant.RequestParamKeys; import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.server.reactive.ServerHttpRequest; @@ -79,11 +77,11 @@ public class ExtAppTakeTokenAuthProcessor extends ExtAppAuthProcessor { EpmetCommonServiceOpenFeignClient commonService = SpringContextUtils.getBean(EpmetCommonServiceOpenFeignClient.class); Result result = commonService.getSecret(appId); if (result == null || !result.success()) { - throw new RenException("fetchToken方式的外部应用认证,获取secret失败"); + throw new RenException("TakeToken方式的外部应用认证,获取secret失败"); } String secret = result.getData(); if (StringUtils.isBlank(secret)) { - throw new RenException("fetchToken方式的外部应用认证,获取secret失败"); + throw new RenException("TakeToken方式的外部应用认证,获取secret失败"); } return secret; diff --git a/epmet-gateway/src/main/java/com/epmet/filter/CpAuthGatewayFilterFactory.java b/epmet-gateway/src/main/java/com/epmet/filter/CpAuthGatewayFilterFactory.java index c9a19fa8b8..6513d27f04 100644 --- a/epmet-gateway/src/main/java/com/epmet/filter/CpAuthGatewayFilterFactory.java +++ b/epmet-gateway/src/main/java/com/epmet/filter/CpAuthGatewayFilterFactory.java @@ -5,6 +5,7 @@ import com.alibaba.fastjson.JSON; import com.epmet.auth.ExternalAuthProcessor; import com.epmet.auth.InternalAuthProcessor; import com.epmet.commons.tools.constant.AppClientConstant; +import com.epmet.commons.tools.exception.ExceptionUtils; import com.epmet.commons.tools.exception.RenException; import com.epmet.commons.tools.utils.IpUtils; import com.epmet.commons.tools.utils.Result; @@ -26,13 +27,13 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.stereotype.Component; +import org.springframework.util.MultiValueMap; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.List; +import java.util.*; /** * app接口权限过滤器 @@ -43,152 +44,197 @@ import java.util.List; @Component("CpAuth") public class CpAuthGatewayFilterFactory extends AbstractGatewayFilterFactory { - private Logger logger = LoggerFactory.getLogger(getClass()); - - @Autowired - private InternalAuthProcessor internalAuthProcessor; - - @Autowired - private ExternalAuthProcessor externalAuthProcessor; - - @Override - public List shortcutFieldOrder() { - return Arrays.asList("enabled"); - } - - public CpAuthGatewayFilterFactory() { - super(CpAuthConfig.class); - } - - @Override - public GatewayFilter apply(CpAuthConfig config) { - return (exchange, chain) -> { - if (!config.isEnabled()) { - return chain.filter(exchange); - } - - //添加流水号 - ServerHttpRequest request = exchange.getRequest(); - List tranSerials = request.getHeaders().get(AppClientConstant.TRANSACTION_SERIAL_KEY); - if (CollectionUtils.isEmpty(tranSerials) || StringUtils.isBlank(tranSerials.get(0))) { - request.mutate().header(AppClientConstant.TRANSACTION_SERIAL_KEY, new String[]{getTransactionSerial()}); - } - - String authType = getAuthType(request); - String requestUri = request.getPath().pathWithinApplication().value(); - - logger.info("CpAuthGatewayFilterFactory当前requestUri=[" + requestUri + "],CpAuthGatewayFilterFactory拦截成功,客户端Id:{}", IpUtils.getClientIp(request)); - try { - switch (authType) { - case AuthTypeConstant.AUTH_TYPE_ALL: - externalAuthProcessor.auth(exchange, chain); - internalAuthProcessor.auth(exchange, chain); - break; - case AuthTypeConstant.AUTH_TYPE_EXTERNAL: - externalAuthProcessor.auth(exchange, chain); - break; - case AuthTypeConstant.AUTH_TYPE_INTERNAL: - internalAuthProcessor.auth(exchange, chain); - break; - } - } catch (RenException e) { - return response(exchange, new Result<>().error(e.getCode(), e.getMessage())); - } catch (Exception e) { - return response(exchange, new Result<>().error(e.getMessage())); - } - - return chain.filter(exchange); - }; - } - - /** - * 判断需要执行的认证方式(内部应用认证还是外部应用认证) - * @return - */ - private String getAuthType(ServerHttpRequest request) { - //String requestUri = request.getPath().pathWithinApplication().value(); - - // 是否在外部认证列表中(外部认证列表中的url,是对外部应用开放的,只有在这个列表中的url才对外部应用开放) - //boolean inExtAuthPaths = false; - // - //for (String url : cpProperty.getExternalAuthUrls()) { - // if (antPathMatcher.match(url, requestUri)) { - // inExtAuthPaths = true; - // } - //} - - String authType = ServerHttpRequestUtils.getRequestParam(request, RequestParamKeys.AUTH_TYPE); - if (StringUtils.isNotBlank(authType) && AuthTypes.TAKE_TOKEN.equals(authType)) { - return AuthTypeConstant.AUTH_TYPE_EXTERNAL; - } - - boolean needExternal = StringUtils.isNotBlank(request.getHeaders().getFirst(TokenHeaderKeyConstant.ACCESS_TOKEN_HEADER_KEY)); - boolean needInternal = StringUtils.isNotBlank(request.getHeaders().getFirst(TokenHeaderKeyConstant.AUTHORIZATION_TOKEN_HEADER_KEY)); - - if (needExternal && needInternal) { - return AuthTypeConstant.AUTH_TYPE_ALL; - } - - if (needExternal) { - // url对外部应用开放,并且头里面有AccessToken,那么走外部应用认证 - return AuthTypeConstant.AUTH_TYPE_EXTERNAL; - } - - return AuthTypeConstant.AUTH_TYPE_INTERNAL; - } - - /** - * 获取请求头 - * @param request - * @return - */ - private String getHeader(ServerHttpRequest request, String headerName) { - HttpHeaders headers = request.getHeaders(); - return headers.getFirst(headerName); - } - - /** - * 获取事务流水号 - * @return - */ - public static String getTransactionSerial() { - String[] letterPool = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n" - , "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"}; - - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < 2; i++) { - sb.append(letterPool[(int) (Math.random() * 25)]); - } - - sb.append(System.currentTimeMillis()); - return sb.toString(); - } - - public static class CpAuthConfig { - - /** - * 控制是否开启认证 - */ - private boolean enabled; - - public CpAuthConfig() { - } - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - } - - protected Mono response(ServerWebExchange exchange, Object object) { - String json = JSON.toJSONString(object); - DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(json.getBytes(StandardCharsets.UTF_8)); - exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON_UTF8); - exchange.getResponse().setStatusCode(HttpStatus.OK); - return exchange.getResponse().writeWith(Flux.just(buffer)); - } + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private InternalAuthProcessor internalAuthProcessor; + + @Autowired + private ExternalAuthProcessor externalAuthProcessor; + + @Override + public List shortcutFieldOrder() { + return Arrays.asList("enabled"); + } + + public CpAuthGatewayFilterFactory() { + super(CpAuthConfig.class); + } + + @Override + public GatewayFilter apply(CpAuthConfig config) { + return (exchange, chain) -> { + if (!config.isEnabled()) { + return chain.filter(exchange); + } + + //1.添加流水号 + ServerHttpRequest request = exchange.getRequest(); + List tranSerials = request.getHeaders().get(AppClientConstant.TRANSACTION_SERIAL_KEY); + if (CollectionUtils.isEmpty(tranSerials) || StringUtils.isBlank(tranSerials.get(0))) { + request.mutate().header(AppClientConstant.TRANSACTION_SERIAL_KEY, new String[]{getTransactionSerial()}); + } + + //2.获取请求路径,参数 + String requestUri = request.getPath().pathWithinApplication().value(); + MultiValueMap queryParams = request.getQueryParams(); + String queryParamsStr = convertQueryParams2String(queryParams); + logger.info("CpAuthGatewayFilterFactory当前requestUri=[" + requestUri.concat(queryParamsStr) + "],CpAuthGatewayFilterFactory拦截成功,客户端Id:{}", IpUtils.getClientIp(request)); + + //3.认证 + String authType = getAuthType(request); + logger.info("认证类型为:{}", authType); + try { + switch (authType) { + case AuthTypeConstant.AUTH_TYPE_ALL: + externalAuthProcessor.auth(exchange, chain); + internalAuthProcessor.auth(exchange, chain); + break; + case AuthTypeConstant.AUTH_TYPE_EXTERNAL: + externalAuthProcessor.auth(exchange, chain); + break; + case AuthTypeConstant.AUTH_TYPE_INTERNAL: + internalAuthProcessor.auth(exchange, chain); + break; + } + } catch (RenException e) { + logger.error("CpAuthGatewayFilterFactory认证出错,错误信息:{}", ExceptionUtils.getErrorStackTrace(e)); + return response(exchange, new Result<>().error(e.getCode(), e.getMessage())); + } catch (Exception e) { + logger.error("CpAuthGatewayFilterFactory认证出错,错误信息:{}", ExceptionUtils.getErrorStackTrace(e)); + return response(exchange, new Result<>().error(e.getMessage())); + } + + return chain.filter(exchange); + }; + } + + /** + * @return + * @Description 将url参数转化为String + * @author wxz + * @date 2021.08.11 23:12 + */ + private String convertQueryParams2String(MultiValueMap queryParams) { + try { + if (queryParams == null || queryParams.size() == 0) { + return ""; + } + StringBuilder sb = new StringBuilder(""); + queryParams.entrySet().forEach(entry -> { + String key = entry.getKey(); + List values = entry.getValue(); + + String value = ""; + if (values != null && values.size() > 0) { + value = values.get(0); + } + + sb.append("&").append(key).append("=").append(value); + }); + String result = sb.toString(); + if (result.startsWith("&")) { + result = result.substring(1); + return "?".concat(result); + } + return ""; + } catch (Exception e) { + logger.warn("gateway中将url参数转化为String失败,程序继续执行,错误信息:".concat(ExceptionUtils.getErrorStackTrace(e))); + return ""; + } + } + + /** + * 判断需要执行的认证方式(内部应用认证还是外部应用认证) + * + * @return + */ + private String getAuthType(ServerHttpRequest request) { + //String requestUri = request.getPath().pathWithinApplication().value(); + + // 是否在外部认证列表中(外部认证列表中的url,是对外部应用开放的,只有在这个列表中的url才对外部应用开放) + //boolean inExtAuthPaths = false; + // + //for (String url : cpProperty.getExternalAuthUrls()) { + // if (antPathMatcher.match(url, requestUri)) { + // inExtAuthPaths = true; + // } + //} + + String authType = ServerHttpRequestUtils.getRequestParam(request, RequestParamKeys.AUTH_TYPE); + if (StringUtils.isNotBlank(authType) && AuthTypes.TAKE_TOKEN.equals(authType)) { + return AuthTypeConstant.AUTH_TYPE_EXTERNAL; + } + + boolean needExternal = StringUtils.isNotBlank(request.getHeaders().getFirst(TokenHeaderKeyConstant.ACCESS_TOKEN_HEADER_KEY)); + boolean needInternal = StringUtils.isNotBlank(request.getHeaders().getFirst(TokenHeaderKeyConstant.AUTHORIZATION_TOKEN_HEADER_KEY)); + + if (needExternal && needInternal) { + return AuthTypeConstant.AUTH_TYPE_ALL; + } + + if (needExternal) { + // url对外部应用开放,并且头里面有AccessToken,那么走外部应用认证 + return AuthTypeConstant.AUTH_TYPE_EXTERNAL; + } + + return AuthTypeConstant.AUTH_TYPE_INTERNAL; + } + + /** + * 获取请求头 + * + * @param request + * @return + */ + private String getHeader(ServerHttpRequest request, String headerName) { + HttpHeaders headers = request.getHeaders(); + return headers.getFirst(headerName); + } + + /** + * 获取事务流水号 + * + * @return + */ + public static String getTransactionSerial() { + String[] letterPool = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n" + , "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"}; + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 2; i++) { + sb.append(letterPool[(int) (Math.random() * 25)]); + } + + sb.append(System.currentTimeMillis()); + return sb.toString(); + } + + public static class CpAuthConfig { + + /** + * 控制是否开启认证 + */ + private boolean enabled; + + public CpAuthConfig() { + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + } + + protected Mono response(ServerWebExchange exchange, Object object) { + String json = JSON.toJSONString(object); + DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(json.getBytes(StandardCharsets.UTF_8)); + exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON_UTF8); + exchange.getResponse().setStatusCode(HttpStatus.OK); + return exchange.getResponse().writeWith(Flux.just(buffer)); + } }