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>
This commit is contained in:
parent
2eecd3ac6a
commit
08676c4f6e
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>());
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue