当前位置:   article > 正文

开放平台控制怎么做_serveraccessdeniedhandler

serveraccessdeniedhandler

1.开放平台业务逻辑

场景:公司构建paas层(能力层),包括:表单服务、im服务、文件服务等;

目标:开发能力给第三方企业使用,同时允许第三方企业已供应商的身份将自己的服务融入到paas层中;

实现:

        平台层面:

                用户服务做鉴权

                网关服务做控制;

                管理服务做配置;

                云市场做购买;

第三方供应商A申请文件服务入驻到开放平台,提供服务域名(https://www.wenjian.com),并实现购买通知相应逻辑(支付成功之后平台会使用域名+固定url同步消息到第三方供应商),应用开通逻辑(开通应用的时候,会推送相应的消息给供应商);

公司运维人员登录开放平台管理后台,创建开发者账号A,生成相应的appid、appsecret,提供给第三方供应商A;创建文件服务应用(供应商类),配置路由规则(/third/party/wj/**->https://www.wenjian.com/**),并将账号信息推送至开放平台云市场;

企业B想使用文件服务能力,访问开放平台云市场,搜索文件服务,找到两个商品(平台自研的,第三方供应商A提供的),首先注册账号(企业、个人),并进行认证,将企业B信息同步至开放平台审核列表中;

公司运营人员登录开放平台运营后台,打开审核列表,审核企业B,通过之后,自动创建一个开发者账号B;

于此同时企业B购买了文件服务商品(第三方文件服务能力),支付成功之后将消息同步至开放平台;企业B点击文件服务,进入到文件服务管理(商品管理)中,创建应用,获取到平台的appid、appsecret,同时平台将此消息同步至第三方供应商A;

企业B使用appid、appsecret秘钥经过认证之后,调取文件服务相应接口。接口请求到达网关的时候,网关根据第三方应用配置,进行并发控制,加密验签设置,将请求转发至相应的域名,并在header中写入平台相应的认证信息;

todo...

流程图


2.网关控制
 

基于oauth2.0协议,网关层引入spring-security-oauth2进行控制;

自定义SecurityWebFilterChain,重写各种类与接口,配置各种过滤器...

  1. @Configuration
  2. public class ResourceServerConfiguration {
  3. private static final String MAX_AGE = "18000L";
  4. @Autowired
  5. private RedisConnectionFactory redisConnectionFactory;
  6. @Autowired
  7. private ResourceLocator apiresourceLocator;
  8. @Autowired
  9. private ApiProperties apiProperties;
  10. @Autowired
  11. private AccessLogService accessLogService;
  12. @Autowired
  13. private BaseAppServiceClient baseAppServiceClient;
  14. /**
  15. * 跨域配置
  16. *
  17. * @return
  18. */
  19. public WebFilter corsFilter() {
  20. return (ServerWebExchange ctx, WebFilterChain chain) -> {
  21. ServerHttpRequest request = ctx.getRequest();
  22. if (CorsUtils.isCorsRequest(request)) {
  23. HttpHeaders requestHeaders = request.getHeaders();
  24. ServerHttpResponse response = ctx.getResponse();
  25. HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();
  26. HttpHeaders headers = response.getHeaders();
  27. headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin());
  28. headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.getAccessControlRequestHeaders());
  29. if (requestMethod != null) {
  30. headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());
  31. }
  32. headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
  33. headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");
  34. headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE);
  35. if (request.getMethod() == HttpMethod.OPTIONS) {
  36. response.setStatusCode(HttpStatus.OK);
  37. return Mono.empty();
  38. }
  39. }
  40. return chain.filter(ctx);
  41. };
  42. }
  43. @Bean
  44. SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) throws Exception {
  45. // 自定义oauth2 认证, 使用redis读取token,而非jwt方式
  46. // 配置应用程序请求身份验证时要执行的操作
  47. // 要使用的入口点
  48. // JsonAuthenticationEntryPoint implements ServerAuthenticationEntryPoint(重写commence方法)
  49. JsonAuthenticationEntryPoint entryPoint = new JsonAuthenticationEntryPoint(accessLogService);
  50. // 配置当经过身份验证的用户未持有所需权限时要执行的操作
  51. // 要使用的拒绝访问处理程序
  52. // JsonAccessDeniedHandler implements ServerAccessDeniedHandler(重写handle方法)
  53. JsonAccessDeniedHandler accessDeniedHandler = new JsonAccessDeniedHandler(accessLogService);
  54. // 自定义授权校验,在此可实现权限控制
  55. // AccessManager implements ReactiveAuthorizationManager<AuthorizationContext>(Authorization,授权管理,重写check方法)
  56. AccessManager accessManager = new AccessManager(apiresourceLocator, apiProperties);
  57. // 自定义认证
  58. // RedisAuthenticationManager implements ReactiveAuthenticationManager(Authentication,认证管理,重写authenticate方法)
  59. AuthenticationWebFilter oauth2 = new AuthenticationWebFilter(new RedisAuthenticationManager(new RedisTokenStore(redisConnectionFactory)));
  60. oauth2.setServerAuthenticationConverter(new ServerBearerTokenAuthenticationConverter());
  61. oauth2.setAuthenticationFailureHandler(new ServerAuthenticationEntryPointFailureHandler(entryPoint));
  62. oauth2.setAuthenticationSuccessHandler(new ServerAuthenticationSuccessHandler() {
  63. @Override
  64. public Mono<Void> onAuthenticationSuccess(WebFilterExchange webFilterExchange, Authentication authentication) {
  65. ServerWebExchange exchange = webFilterExchange.getExchange();
  66. SecurityContextServerWebExchange securityContextServerWebExchange = new SecurityContextServerWebExchange(exchange, ReactiveSecurityContextHolder.getContext().subscriberContext(
  67. ReactiveSecurityContextHolder.withAuthentication(authentication)
  68. ));
  69. return webFilterExchange.getChain().filter(securityContextServerWebExchange);
  70. }
  71. });
  72. http
  73. .httpBasic().disable()
  74. .csrf().disable()
  75. .authorizeExchange()
  76. .pathMatchers("/").permitAll()
  77. // 动态权限验证
  78. .anyExchange().access(accessManager)
  79. .and().exceptionHandling()
  80. .accessDeniedHandler(accessDeniedHandler)
  81. .authenticationEntryPoint(entryPoint).and()
  82. // 日志前置过滤器
  83. .addFilterAt(new PreRequestFilter(), SecurityWebFiltersOrder.FIRST)
  84. // 跨域过滤器
  85. .addFilterAt(corsFilter(), SecurityWebFiltersOrder.CORS)
  86. // 签名验证过滤器
  87. .addFilterAt(new PreSignatureFilter(baseAppServiceClient, apiProperties, new JsonSignatureDeniedHandler(accessLogService)), SecurityWebFiltersOrder.CSRF)
  88. // 访问验证前置过滤器
  89. .addFilterAt(new PreCheckFilter(accessManager, accessDeniedHandler), SecurityWebFiltersOrder.CSRF)
  90. // oauth2认证过滤器
  91. .addFilterAt(oauth2, SecurityWebFiltersOrder.AUTHENTICATION)
  92. // 日志过滤器
  93. .addFilterAt(new AccessLogFilter(accessLogService), SecurityWebFiltersOrder.SECURITY_CONTEXT_SERVER_WEB_EXCHANGE);
  94. return http.build();
  95. }
  96. }

扩展:oauth2.0

 业务场景:

 oauth2的四种模式

授权码模式示例:

3.动态配置(动态路由、动态限流)

动态路由:

InMemoryRouteDefinitionRepository该接口继承了RouteDefinitionWriter,RouteDefinitionWriter中定义了save、delete方法,通过方法名称可以知道是用来保存/添加/删除路由信息;使用 InMemoryRouteDefinitionRepository 来维护 RouteDefinition 信息,在网关实例重启或者崩溃后,RouteDefinition 就会丢失。

实现方案:
        1.我们可以实现 RouteDefinitionRepository 接口,以实现例如 MySQLRouteDefinitionRepository;
        2.或者基于InMemoryRouteDefinitionRepository 结合MySQL实现路由信息的数据库存储;


本文采用方案2实现,InMemoryRouteDefinitionRepository+MySQL+ApplicationEvent:
定义一个监听事件RefreshRouteEvent:
  1. /**
  2. * 自定义网关刷新事件
  3. */
  4. public class RefreshRouteEvent extends RemoteApplicationEvent {
  5. private RefreshRouteEvent() {
  6. }
  7. public RefreshRouteEvent(Object source, String originService, String destinationService) {
  8. super(source, originService, destinationService);
  9. }
  10. }
定义一个监听RefreshRouteEventListener:
  1. import lombok.extern.slf4j.Slf4j;
  2. import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
  3. import org.springframework.cloud.gateway.filter.FilterDefinition;
  4. import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
  5. import org.springframework.cloud.gateway.route.InMemoryRouteDefinitionRepository;
  6. import org.springframework.cloud.gateway.route.RouteDefinition;
  7. import org.springframework.cloud.gateway.support.NameUtils;
  8. import org.springframework.context.ApplicationEventPublisher;
  9. import org.springframework.context.ApplicationEventPublisherAware;
  10. import org.springframework.context.ApplicationListener;
  11. import org.springframework.jdbc.core.JdbcTemplate;
  12. import org.springframework.jdbc.core.RowMapper;
  13. import org.springframework.web.util.UriComponentsBuilder;
  14. import reactor.core.publisher.Mono;
  15. import java.net.URI;
  16. import java.sql.ResultSet;
  17. import java.sql.SQLException;
  18. import java.util.HashMap;
  19. import java.util.List;
  20. import java.util.Map;
  21. /**
  22. * 动态路由监听器
  23. */
  24. @Slf4j
  25. public class RefreshRouteEventListener implements ApplicationListener<RefreshRouteEvent>, ApplicationEventPublisherAware {
  26. private JdbcTemplate jdbcTemplate;
  27. private ApplicationEventPublisher publisher;
  28. private InMemoryRouteDefinitionRepository repository;
  29. //查询路由的sql
  30. private final static String SELECT_ROUTES = "SELECT * FROM gateway_route WHERE status = 1";
  31. //初始化监听器
  32. public RefreshRouteEventListener(JdbcTemplate jdbcTemplate, InMemoryRouteDefinitionRepository repository) {
  33. this.jdbcTemplate = jdbcTemplate;
  34. this.repository = repository;
  35. }
  36. /**
  37. * 刷新路由
  38. *
  39. * @return
  40. */
  41. public Mono<Void> refresh() {
  42. //从数据库中加载路由到InMemoryRouteDefinitionRepository中
  43. this.loadRoutes();
  44. //触发默认路由刷新事件,刷新缓存路由
  45. this.publisher.publishEvent(new RefreshRoutesEvent(this));
  46. return Mono.empty();
  47. }
  48. /**
  49. * 监听器监听到之间之后执行的业务
  50. *
  51. * @param event
  52. */
  53. @Override
  54. public void onApplicationEvent(RefreshRouteEvent event) {
  55. refresh();
  56. }
  57. /**
  58. * 加载路由
  59. * @return
  60. */
  61. private Mono<Void> loadRoutes() {
  62. //从数据库拿到路由配置
  63. try {
  64. //查询数据库获得路由列表
  65. List<GatewayRoute> routeList = jdbcTemplate.query(SELECT_ROUTES, new RowMapper<GatewayRoute>() {
  66. @Override
  67. public GatewayRoute mapRow(ResultSet rs, int i) throws SQLException {
  68. GatewayRoute result = new GatewayRoute();
  69. result.setRouteId(rs.getLong("route_id"));
  70. result.setPath(rs.getString("path"));
  71. result.setServiceId(rs.getString("service_id"));
  72. result.setUrl(rs.getString("url"));
  73. result.setStatus(rs.getInt("status"));
  74. result.setRetryable(rs.getInt("retryable"));
  75. result.setStripPrefix(rs.getInt("strip_prefix"));
  76. result.setIsPersist(rs.getInt("is_persist"));
  77. result.setRouteName(rs.getString("route_name"));
  78. return result;
  79. }
  80. });
  81. if (routeList != null) {
  82. //加载路由
  83. routeList.forEach(gatewayRoute -> {
  84. RouteDefinition definition = new RouteDefinition();
  85. List<PredicateDefinition> predicates = Lists.newArrayList();
  86. List<FilterDefinition> filters = Lists.newArrayList();
  87. definition.setId(gatewayRoute.getRouteName());
  88. //路由地址
  89. PredicateDefinition predicatePath = new PredicateDefinition();
  90. Map<String, String> predicatePathParams = new HashMap<>(8);
  91. predicatePath.setName("Path");
  92. //predicates.name
  93. predicatePathParams.put("name", StringUtils.isBlank(gatewayRoute.getRouteName()) ? gatewayRoute.getRouteId().toString() : gatewayRoute.getRouteName());
  94. //predicates.args.pattern
  95. predicatePathParams.put("pattern", gatewayRoute.getPath());
  96. //predicates.args.pathPattern
  97. predicatePathParams.put("pathPattern", gatewayRoute.getPath());
  98. //predicates.args
  99. predicatePath.setArgs(predicatePathParams);
  100. predicates.add(predicatePath);
  101. //服务地址,url:完整地址,serviceId:服务ID;
  102. //配置完整地址的使用完整地址,否则使用服务ID;
  103. URI uri = UriComponentsBuilder.fromUriString(StringUtils.isNotBlank(gatewayRoute.getUrl()) ? gatewayRoute.getUrl() : "lb://" + gatewayRoute.getServiceId()).build().toUri();
  104. FilterDefinition stripPrefixDefinition = new FilterDefinition();
  105. Map<String, String> stripPrefixParams = new HashMap<>(8);
  106. //StripPrefix参数表示在将请求发送到下游之前从请求中剥离的路径个数
  107. stripPrefixDefinition.setName("StripPrefix");
  108. stripPrefixParams.put(NameUtils.GENERATED_NAME_PREFIX + "0", "1");
  109. stripPrefixDefinition.setArgs(stripPrefixParams);
  110. filters.add(stripPrefixDefinition);
  111. //yml配置中的predicates
  112. definition.setPredicates(predicates);
  113. //yml配置中的filters
  114. definition.setFilters(filters);
  115. definition.setUri(uri);
  116. this.repository.save(Mono.just(definition)).subscribe();
  117. });
  118. }
  119. log.info("=============加载动态路由:{}==============", routeList.size());
  120. } catch (Exception e) {
  121. log.error("加载动态路由错误:{}", e);
  122. }
  123. return Mono.empty();
  124. }
  125. @Override
  126. public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
  127. this.publisher = applicationEventPublisher;
  128. }
  129. }
  1. import com.baomidou.mybatisplus.annotation.IdType;
  2. import com.baomidou.mybatisplus.annotation.TableId;
  3. import com.baomidou.mybatisplus.annotation.TableName;
  4. import lombok.Data;
  5. import lombok.EqualsAndHashCode;
  6. import lombok.NoArgsConstructor;
  7. /**
  8. * 网关动态路由
  9. */
  10. @Data
  11. @EqualsAndHashCode(callSuper = true)
  12. @NoArgsConstructor
  13. @TableName("gateway_route")
  14. public class GatewayRoute extends AbstractEntity {
  15. private static final long serialVersionUID = -2952097064941740301L;
  16. /**
  17. * 路由ID
  18. */
  19. @TableId(type = IdType.ID_WORKER)
  20. private Long routeId;
  21. /**
  22. * 路由名称
  23. */
  24. private String routeName;
  25. /**
  26. * 路径
  27. */
  28. private String path;
  29. /**
  30. * 服务ID
  31. */
  32. private String serviceId;
  33. /**
  34. * 完整地址
  35. */
  36. private String url;
  37. /**
  38. * 忽略前缀
  39. */
  40. private Integer stripPrefix;
  41. /**
  42. * 0-不重试 1-重试
  43. */
  44. private Integer retryable;
  45. /**
  46. * 状态:0-无效 1-有效
  47. */
  48. private Integer status;
  49. /**
  50. * 保留数据0-否 1-是 不允许删除
  51. */
  52. private Integer isPersist;
  53. /**
  54. * 路由说明
  55. */
  56. private String routeDesc;
  57. }
动态刷新1:
  1. import org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint;
  2. import org.springframework.cloud.bus.endpoint.AbstractBusEndpoint;
  3. import org.springframework.context.ApplicationEventPublisher;
  4. import org.springframework.web.bind.annotation.PostMapping;
  5. import org.springframework.web.bind.annotation.RequestParam;
  6. /**
  7. * 自定义网关监控端点
  8. */
  9. @RestControllerEndpoint(
  10. id = "open"
  11. )
  12. public class ApiEndpoint extends AbstractBusEndpoint {
  13. public ApiEndpoint(ApplicationEventPublisher context, String id) {
  14. super(context, id);
  15. }
  16. /**
  17. * 动态刷新
  18. */
  19. @PostMapping("/refresh")
  20. public ResultBody busRefreshWithDestination(@RequestParam(required = false) String destination) {
  21. this.publish(new RefreshRouteEvent(this, this.getInstanceId(), destination));
  22. return ResultBody.ok();
  23. }
  24. }
动态刷新2:
  1. import lombok.extern.slf4j.Slf4j;
  2. import org.springframework.cloud.bus.BusProperties;
  3. import org.springframework.context.ApplicationEventPublisher;
  4. import org.springframework.web.client.RestTemplate;
  5. /**
  6. * 自定义请求工具类
  7. */
  8. @Slf4j
  9. public class OpenRestTemplate extends RestTemplate {
  10. private ApplicationEventPublisher publisher;
  11. private BusProperties busProperties;
  12. public OpenRestTemplate(BusProperties busProperties, ApplicationEventPublisher publisher) {
  13. this.publisher = publisher;
  14. this.busProperties = busProperties;
  15. }
  16. /**
  17. * 刷新网关
  18. */
  19. public void refreshGateway() {
  20. try {
  21. publisher.publishEvent(new RefreshRouteEvent(this, busProperties.getId(), null));
  22. log.info("refreshGateway:success");
  23. } catch (Exception e) {
  24. log.error("refreshGateway error:{}", e.getMessage());
  25. }
  26. }
  27. }
  1. import io.swagger.annotations.Api;
  2. import io.swagger.annotations.ApiOperation;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.web.bind.annotation.PostMapping;
  5. import org.springframework.web.bind.annotation.RestController;
  6. /**
  7. * 系统接口资源管理
  8. */
  9. @Api(tags = "系统接口资源管理")
  10. @RestController
  11. public class BaseApiController {
  12. @Autowired
  13. private OpenRestTemplate openRestTemplate;
  14. /**
  15. * 刷新网关
  16. */
  17. @ApiOperation(value = "刷新网关", notes = "刷新网关")
  18. @PostMapping("/refreshGateway")
  19. public ResultBody refreshGateway() {
  20. //刷新网关
  21. openRestTemplate.refreshGateway();
  22. return ResultBody.ok();
  23. }
  24. }

动态限流:

实现方案与动态路由一致,修改动态路由中的loadRoutes()方法(从数据库中获取限流规则,与路由定义绑定,满足每个路由都有自己的限流规则):

底层:基于RequestRateLimiter,spring cloud  gateway 的 RequestRateLimiter 使用令牌桶算法来控制请求速率;

限流算法:令牌桶;系统会以一定的速度生成令牌,并将其放置到令牌桶中,可以将令牌桶想象成一个缓冲区(可以用队列这种数据结构来实现),当缓冲区填满的时候,新生成的令牌会被扔掉(除了要求能够限制数据的平均传输速率外,还允许某种程度的突发传输):
      第一个是生成令牌的速度,一般称为 rate 。比如,我们设定 rate = 2 ,即每秒钟生成 2 个令牌,也就是每 1/2 秒生成一个令牌;
      第二个是令牌桶的大小,一般称为 burst 。比如,我们设定 burst = 10 ,即令牌桶最大只能容纳 10 个令牌。

扩展:漏桶算法,漏桶算法思路很简单,水(请求)先进入到漏桶里,漏桶以一定的速度出水,当水流入速度过大会直接溢出,可以看出漏桶算法能强行限制数据的传输速率。

replenishRate:你允许用户每秒执行多少请求,而不丢弃任何请求,这是令牌桶的填充速率;

burstCapacity:允许用户在一秒钟内执行的最大请求数。这是令牌桶可以保存的令牌数,将此值设置为零将阻止所有请求;
  1. private Mono<Void> loadRoutes() {
  2. //从数据库拿到路由配置
  3. try {
  4. List<GatewayRoute> routeList = jdbcTemplate.query(SELECT_ROUTES, new RowMapper<GatewayRoute>() {
  5. @Override
  6. public GatewayRoute mapRow(ResultSet rs, int i) throws SQLException {
  7. GatewayRoute result = new GatewayRoute();
  8. result.setRouteId(rs.getLong("route_id"));
  9. result.setPath(rs.getString("path"));
  10. result.setServiceId(rs.getString("service_id"));
  11. result.setUrl(rs.getString("url"));
  12. result.setStatus(rs.getInt("status"));
  13. result.setRetryable(rs.getInt("retryable"));
  14. result.setStripPrefix(rs.getInt("strip_prefix"));
  15. result.setIsPersist(rs.getInt("is_persist"));
  16. result.setRouteName(rs.getString("route_name"));
  17. return result;
  18. }
  19. });
  20. List<RateLimitApi> limitApiList = jdbcTemplate.query(SELECT_LIMIT_PATH, new RowMapper<RateLimitApi>() {
  21. @Override
  22. public RateLimitApi mapRow(ResultSet rs, int i) throws SQLException {
  23. RateLimitApi result = new RateLimitApi();
  24. result.setPolicyId(rs.getLong("policy_id"));
  25. result.setPolicyName(rs.getString("policy_name"));
  26. result.setServiceId(rs.getString("service_id"));
  27. result.setPath(rs.getString("path"));
  28. result.setApiId(rs.getLong("api_id"));
  29. result.setApiCode(rs.getString("api_code"));
  30. result.setApiName(rs.getString("api_name"));
  31. result.setApiCategory(rs.getString("api_category"));
  32. result.setLimitQuota(rs.getLong("limit_quota"));
  33. result.setIntervalUnit(rs.getString("interval_unit"));
  34. result.setUrl(rs.getString("url"));
  35. return result;
  36. }
  37. });
  38. if (limitApiList != null) {
  39. // 加载限流
  40. limitApiList.forEach(item -> {
  41. long[] arry = ResourceLocator.getIntervalAndQuota(item.getIntervalUnit());
  42. Long refreshInterval = arry[0];
  43. Long quota = arry[1];
  44. // 允许用户每秒处理多少个请求
  45. long replenishRate = item.getLimitQuota() / refreshInterval;
  46. replenishRate = replenishRate < 1 ? 1 : refreshInterval;
  47. // 令牌桶的容量,允许在一秒钟内完成的最大请求数
  48. long burstCapacity = replenishRate * 2;
  49. RouteDefinition definition = new RouteDefinition();
  50. List<PredicateDefinition> predicates = Lists.newArrayList();
  51. List<FilterDefinition> filters = Lists.newArrayList();
  52. definition.setId(item.getApiId().toString());
  53. PredicateDefinition predicatePath = new PredicateDefinition();
  54. String fullPath = getFullPath(routeList, item.getServiceId(), item.getPath());
  55. Map<String, String> predicatePathParams = new HashMap<>(8);
  56. predicatePath.setName("Path");
  57. predicatePathParams.put("pattern", fullPath);
  58. predicatePathParams.put("pathPattern", fullPath);
  59. predicatePathParams.put("_rateLimit", "1");
  60. predicatePath.setArgs(predicatePathParams);
  61. predicates.add(predicatePath);
  62. // 服务地址
  63. URI uri = UriComponentsBuilder.fromUriString(StringUtils.isNotBlank(item.getUrl()) ? item.getUrl() : "lb://" + item.getServiceId()).build().toUri();
  64. // 路径去前缀
  65. FilterDefinition stripPrefixDefinition = new FilterDefinition();
  66. Map<String, String> stripPrefixParams = new HashMap<>(8);
  67. stripPrefixDefinition.setName("StripPrefix");
  68. stripPrefixParams.put(NameUtils.GENERATED_NAME_PREFIX + "0", "1");
  69. stripPrefixDefinition.setArgs(stripPrefixParams);
  70. filters.add(stripPrefixDefinition);
  71. // 限流
  72. FilterDefinition rateLimiterDefinition = new FilterDefinition();
  73. Map<String, String> rateLimiterParams = new HashMap<>(8);
  74. rateLimiterDefinition.setName("RequestRateLimiter");
  75. //令牌桶流速
  76. rateLimiterParams.put("redis-rate-limiter.replenishRate", String.valueOf(replenishRate));
  77. //令牌桶容量
  78. rateLimiterParams.put("redis-rate-limiter.burstCapacity", String.valueOf(burstCapacity));
  79. //限流策略(#{@BeanName})
  80. rateLimiterParams.put("key-resolver", "#{@pathKeyResolver}");
  81. rateLimiterDefinition.setArgs(rateLimiterParams);
  82. //限流策略与filters绑定
  83. filters.add(rateLimiterDefinition);
  84. //指定限流prodicates
  85. definition.setPredicates(predicates);
  86. //filters与路由定义绑定
  87. definition.setFilters(filters);
  88. definition.setUri(uri);
  89. this.repository.save(Mono.just(definition)).subscribe();
  90. });
  91. }
  92. log.info("=============加载动态路由:{}==============", routeList.size());
  93. log.info("=============加载动态限流:{}==============", limitApiList.size());
  94. } catch (Exception e) {
  95. log.error("加载动态路由错误:{}", e);
  96. }
  97. return Mono.empty();
  98. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/68896
推荐阅读
相关标签
  

闽ICP备14008679号