Bladeren bron

Support parsing cookie as request items in gateway flow control (#814)

- Add `getCookieValue` method in RequestItemParser interface and update GatewayParamParser
- Add cookie parsing logic for Spring Cloud Gateway and Zuul

Signed-off-by: Eric Zhao <sczyh16@gmail.com>
master
Eric Zhao GitHub 5 jaren geleden
bovenliggende
commit
08676c4f6e
Geen bekende sleutel gevonden voor deze handtekening in de database GPG sleutel-ID: 4AEE18F83AFDEB23
7 gewijzigde bestanden met toevoegingen van 83 en 11 verwijderingen
  1. +1
    -0
      sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/SentinelGatewayConstants.java
  2. +15
    -2
      sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/param/GatewayParamParser.java
  3. +12
    -2
      sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/param/RequestItemParser.java
  4. +10
    -5
      sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/rule/GatewayRuleManager.java
  5. +20
    -2
      sentinel-adapter/sentinel-api-gateway-adapter-common/src/test/java/com/alibaba/csp/sentinel/adapter/gateway/common/param/GatewayParamParserTest.java
  6. +9
    -0
      sentinel-adapter/sentinel-spring-cloud-gateway-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/sc/ServerWebExchangeItemParser.java
  7. +16
    -0
      sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/zuul/RequestContextItemParser.java

+ 1
- 0
sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/SentinelGatewayConstants.java Bestand weergeven

@@ -30,6 +30,7 @@ public final class SentinelGatewayConstants {
public static final int PARAM_PARSE_STRATEGY_HOST = 1;
public static final int PARAM_PARSE_STRATEGY_HEADER = 2;
public static final int PARAM_PARSE_STRATEGY_URL_PARAM = 3;
public static final int PARAM_PARSE_STRATEGY_COOKIE = 4;

public static final int PARAM_MATCH_STRATEGY_EXACT = 0;
public static final int PARAM_MATCH_STRATEGY_PREFIX = 1;


+ 15
- 2
sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/param/GatewayParamParser.java Bestand weergeven

@@ -42,8 +42,8 @@ public class GatewayParamParser<T> {
/**
* Parse parameters for given resource from the request entity on condition of the rule predicate.
*
* @param resource valid resource name
* @param request valid request
* @param resource valid resource name
* @param request valid request
* @param rulePredicate rule predicate indicating the rules to refer
* @return the parameter array
*/
@@ -92,6 +92,8 @@ public class GatewayParamParser<T> {
return parseHeader(item, request);
case SentinelGatewayConstants.PARAM_PARSE_STRATEGY_URL_PARAM:
return parseUrlParameter(item, request);
case SentinelGatewayConstants.PARAM_PARSE_STRATEGY_COOKIE:
return parseCookie(item, request);
default:
return null;
}
@@ -139,6 +141,17 @@ public class GatewayParamParser<T> {
return parseWithMatchStrategyInternal(item.getMatchStrategy(), param, pattern);
}

private String parseCookie(/*@Valid*/ GatewayParamFlowItem item, T request) {
String cookieName = item.getFieldName();
String pattern = item.getPattern();
String param = requestItemParser.getCookieValue(request, cookieName);
if (pattern == null) {
return param;
}
// Match value according to regex pattern or exact mode.
return parseWithMatchStrategyInternal(item.getMatchStrategy(), param, pattern);
}

private String parseWithMatchStrategyInternal(int matchStrategy, String value, String pattern) {
// TODO: implement here.
if (value == null) {


+ 12
- 2
sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/param/RequestItemParser.java Bestand weergeven

@@ -41,7 +41,7 @@ public interface RequestItemParser<T> {
* Get the header associated with the header key.
*
* @param request valid request
* @param key valid header key
* @param key valid header key
* @return the header
*/
String getHeader(T request, String key);
@@ -49,9 +49,19 @@ public interface RequestItemParser<T> {
/**
* Get the parameter value associated with the parameter name.
*
* @param request valid request
* @param request valid request
* @param paramName valid parameter name
* @return the parameter value
*/
String getUrlParam(T request, String paramName);

/**
* Get the cookie value associated with the cookie name.
*
* @param request valid request
* @param cookieName valid cookie name
* @return the cookie value
* @since 1.7.0
*/
String getCookieValue(T request, String cookieName);
}

+ 10
- 5
sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/rule/GatewayRuleManager.java Bestand weergeven

@@ -16,6 +16,7 @@
package com.alibaba.csp.sentinel.adapter.gateway.common.rule;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -242,14 +243,18 @@ public final class GatewayRuleManager {
if (item.getParseStrategy() < 0) {
return false;
}
if (item.getParseStrategy() == SentinelGatewayConstants.PARAM_PARSE_STRATEGY_URL_PARAM ||
item.getParseStrategy() == SentinelGatewayConstants.PARAM_PARSE_STRATEGY_HEADER) {
if (StringUtil.isBlank(item.getFieldName())) {
return false;
}
// Check required field name for item types.
if (FIELD_REQUIRED_SET.contains(item.getParseStrategy()) && StringUtil.isBlank(item.getFieldName())) {
return false;
}
return StringUtil.isEmpty(item.getPattern()) || item.getMatchStrategy() >= 0;
}

private static final Set<Integer> FIELD_REQUIRED_SET = new HashSet<>(
Arrays.asList(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_URL_PARAM,
SentinelGatewayConstants.PARAM_PARSE_STRATEGY_HEADER,
SentinelGatewayConstants.PARAM_PARSE_STRATEGY_COOKIE)
);

private GatewayRuleManager() {}
}

+ 20
- 2
sentinel-adapter/sentinel-api-gateway-adapter-common/src/test/java/com/alibaba/csp/sentinel/adapter/gateway/common/param/GatewayParamParserTest.java Bestand weergeven

@@ -94,6 +94,7 @@ public class GatewayParamParserTest {
final String api1 = "my_test_route_B";
final String headerName = "X-Sentinel-Flag";
final String paramName = "p";
final String cookieName = "myCookie";
GatewayFlowRule routeRuleNoParam = new GatewayFlowRule(routeId1)
.setCount(10)
.setIntervalSec(10);
@@ -128,6 +129,13 @@ public class GatewayParamParserTest {
.setParamItem(new GatewayParamFlowItem()
.setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_HOST)
);
GatewayFlowRule routeRule5 = new GatewayFlowRule(routeId1)
.setCount(50)
.setIntervalSec(30)
.setParamItem(new GatewayParamFlowItem()
.setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_COOKIE)
.setFieldName(cookieName)
);
GatewayFlowRule apiRule1 = new GatewayFlowRule(api1)
.setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_CUSTOM_API_NAME)
.setCount(5)
@@ -140,6 +148,7 @@ public class GatewayParamParserTest {
rules.add(routeRule2);
rules.add(routeRule3);
rules.add(routeRule4);
rules.add(routeRule5);
rules.add(routeRuleNoParam);
rules.add(apiRule1);
GatewayRuleManager.loadRules(rules);
@@ -148,19 +157,24 @@ public class GatewayParamParserTest {
final String expectedAddress = "66.77.88.99";
final String expectedHeaderValue1 = "Sentinel";
final String expectedUrlParamValue1 = "17";
final String expectedCookieValue1 = "Sentinel-Foo";

mockClientHostAddress(itemParser, expectedAddress);
Map<String, String> expectedHeaders = new HashMap<String, String>() {{
put(headerName, expectedHeaderValue1); put("Host", expectedHost);
}};
mockHeaders(itemParser, expectedHeaders);
mockSingleUrlParam(itemParser, paramName, expectedUrlParamValue1);
mockSingleCookie(itemParser, cookieName, expectedCookieValue1);

Object[] params = paramParser.parseParameterFor(routeId1, request, routeIdPredicate);
// Param length should be 5 (4 with parameters, 1 normal flow with generated constant)
assertThat(params.length).isEqualTo(5);
// Param length should be 6 (5 with parameters, 1 normal flow with generated constant)
assertThat(params.length).isEqualTo(6);
assertThat(params[routeRule1.getParamItem().getIndex()]).isEqualTo(expectedAddress);
assertThat(params[routeRule2.getParamItem().getIndex()]).isEqualTo(expectedHeaderValue1);
assertThat(params[routeRule3.getParamItem().getIndex()]).isEqualTo(expectedUrlParamValue1);
assertThat(params[routeRule4.getParamItem().getIndex()]).isEqualTo(expectedHost);
assertThat(params[routeRule5.getParamItem().getIndex()]).isEqualTo(expectedCookieValue1);
assertThat(params[params.length - 1]).isEqualTo(SentinelGatewayConstants.GATEWAY_DEFAULT_PARAM);

assertThat(paramParser.parseParameterFor(api1, request, routeIdPredicate).length).isZero();
@@ -196,6 +210,10 @@ public class GatewayParamParserTest {
when(parser.getHeader(any(), eq(key))).thenReturn(value);
}

private void mockSingleCookie(/*@Mock*/ RequestItemParser parser, String key, String value) {
when(parser.getCookieValue(any(), eq(key))).thenReturn(value);
}

@Before
public void setUp() {
GatewayApiDefinitionManager.loadApiDefinitions(new HashSet<ApiDefinition>());


+ 9
- 0
sentinel-adapter/sentinel-spring-cloud-gateway-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/sc/ServerWebExchangeItemParser.java Bestand weergeven

@@ -16,9 +16,11 @@
package com.alibaba.csp.sentinel.adapter.gateway.sc;

import java.net.InetSocketAddress;
import java.util.Optional;

import com.alibaba.csp.sentinel.adapter.gateway.common.param.RequestItemParser;

import org.springframework.http.HttpCookie;
import org.springframework.web.server.ServerWebExchange;

/**
@@ -50,4 +52,11 @@ public class ServerWebExchangeItemParser implements RequestItemParser<ServerWebE
public String getUrlParam(ServerWebExchange exchange, String paramName) {
return exchange.getRequest().getQueryParams().getFirst(paramName);
}

@Override
public String getCookieValue(ServerWebExchange exchange, String cookieName) {
return Optional.ofNullable(exchange.getResponse().getCookies().getFirst(cookieName))
.map(HttpCookie::getValue)
.orElse(null);
}
}

+ 16
- 0
sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/zuul/RequestContextItemParser.java Bestand weergeven

@@ -15,6 +15,8 @@
*/
package com.alibaba.csp.sentinel.adapter.gateway.zuul;

import javax.servlet.http.Cookie;

import com.alibaba.csp.sentinel.adapter.gateway.common.param.RequestItemParser;

import com.netflix.zuul.context.RequestContext;
@@ -44,4 +46,18 @@ public class RequestContextItemParser implements RequestItemParser<RequestContex
public String getUrlParam(RequestContext requestContext, String paramName) {
return requestContext.getRequest().getParameter(paramName);
}

@Override
public String getCookieValue(RequestContext requestContext, String cookieName) {
Cookie[] cookies = requestContext.getRequest().getCookies();
if (cookies == null || cookieName == null) {
return null;
}
for (Cookie cookie : cookies) {
if (cookie != null && cookieName.equals(cookie.getName())) {
return cookie.getValue();
}
}
return null;
}
}

Laden…
Annuleren
Opslaan