# Overview

When it is necessary to intercept requests for processing, this can be achieved through the fizz plug-in mechanism.

fizz plugin:

  1. Spring-like WebFilter (can also be understood as filter in the servlet specification, but it is non-blocking).
  2. Different context parameters can be configured for different requests, and the configuration can be completed through the management background.

# Development specifications

A plug-in corresponds to a project and a warehouse, and is released in the form of a jar package, which can then be relied upon by the fizz gateway. See https://github.com/wehotel/fizz-demo-plugin. New plug-ins can be developed using this as a template. It is also a fizz gateway itself, which can be used for plug-in testing directly in the project, as explained below.

  1. Apply for plug-in warehouse

The applicant provides the plug-in name, such as the demo plug-in demo above, and the official creates a warehouse named fizz-demo-plugin. The applicant develops the plug-in under the warehouse. fizz-demo-plugin is also the official name of the plug-in.

  1. Warehouse pom

You can copy the pom of fizz-demo-plugin and adjust:

     <groupId>com.fizzgate</groupId>
     <artifactId>fizz-demo-plugin</artifactId>
     <version>2.3.0-SNAPSHOT</version>

artifactId is the official plug-in name, and version is the corresponding version.

ps: Adjust the exclude below to remove content that has nothing to do with the plug-in.

<plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-jar-plugin</artifactId>
      <configuration>
          <excludes>
              <exclude>*.xml</exclude>
              <exclude>*.yml</exclude>
              <exclude>we/plugin/demo/DemoApiConfig**</exclude>
              <exclude>we/plugin/demo/Main**</exclude>
          </excludes>
      </configuration>
</plugin>
  1. src/resources

You can directly copy the configuration of fizz-demo-plugin and adjust aggregate.redis in application.yml to the redis of the applicant.

  1. src/java

The project root package naming rule is we.plugin.plugin name. For example, in the demo plug-in project above, the root package is we.plugin.demo.

  1. Plug-in logic

Implementing FizzPluginFilter is a fizz plug-in, such as DemoPluginFilter in fizz-demo-plugin. Its function is to intercept the request and output "this is demo plugin".

The fizz-demo-plugin project itself is also a fizz gateway, listening on port 8600 by default.

DemoApiConfig.java (only used for testing in this project) configures a reverse proxy route and binds the demoPlugin (DemoPluginFilter) plug-in. When requesting http://127.0.0.1:8600/proxy/xservice/ypath, the gateway will execute DemoPluginFilter. , and then forward the request to http://127.0.0.1:9094/@ypath. This interface needs to exist and be started. Initiate the method of http://127.0.0.1:8600/proxy/xservice/ypath and http://127.0 .0.1:9094/@ypath supports the same methods, and there are no restrictions in routing configuration.

Main.java (only used for testing this project), run it, and then initiate a http://127.0.0.1:8600/proxy/xservice/ypath request to test the plug-in.

Another testing method is mvn install fizz-demo-plugin, which is introduced and tested in the fizz-bootstrap gateway project similar to fizz-gateway-node. Pay attention to the adjustment of the install jar:

<plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-jar-plugin</artifactId>
      <configuration>
          <excludes>
              <exclude>*.xml</exclude>
              <exclude>*.yml</exclude>
              <exclude>we/plugin/demo/DemoApiConfig**</exclude>
              <exclude>we/plugin/demo/Main**</exclude>
          </excludes>
      </configuration>
</plugin>

Remove configuration and testing content.

  1. Plug-in release

Released by the official government.

The above describes the specifications for plug-in development. The following two parts, gateway development and manager configuration, use an example to introduce the development of plug-in logic.

Example: Assume that after the user logs in to the system, the system generates the corresponding token and stores it in redis in the form of token (key) -> user id (value). The user's subsequent requests must bring the token, otherwise the system logic cannot be accessed. If the The token does not exist in the system and access is denied.

# Gateway development

accomplish

public interface FizzPluginFilter {
     public Mono<Void> filter(ServerWebExchange exchange, Map<String, Object> config);
}

That is, a plug-in is defined, and config receives the parameters configured by the management background (manager).

Example plugin:

@Component(RedisAuthPlugin.REDIS_AUTH_PLUGIN) //Plugin id, required
public class RedisAuthPlugin implements FizzPluginFilter {

     private static final Logger log = LoggerFactory.getLogger(RedisAuthPlugin.class);

     public static final String REDIS_AUTH_PLUGIN = "redisAuthPlugin"; // The management background sets the plug-in id accordingly.

     @Resource(name = RedisConfig.REACTIVE_STRING_REDIS_TEMPLATE)
     private ReactiveStringRedisTemplate redisTemplate;

     @Override
     public Mono<Void> filter(ServerWebExchange exchange, Map<String, Object> config) {
         String customConfig = (String) config.get(PluginConfig.CUSTOM_CONFIG); // Get the customized plug-in configuration of the management background
         log.info("custom plugin config: " + customConfig);
         doSomething();
        
         String tk = exchange.getRequest().getQueryParams().getFirst("token"); // Get the token carried by the client request
         return
                 redisTemplate.opsForValue().get(tk).defaultIfEmpty(Constants.Symbol.EMPTY) // Check whether tk exists in redis
                         .flatMap(
                                 user -> {
                                     if (user == Constants.Symbol.EMPTY) {
                                         return WebUtils.buildDirectResponse(exchange, HttpStatus.OK, null, "token does not exist " + tk); // Reject the current request
                                     } else {
                                         exchange.getAttributes().put("11", "22"); // Pass parameters to subsequent plug-ins or logic
                                         Mono next = FizzPluginFilterChain.next(exchange); // Execute the next plug-in or subsequent logic
                                         return next.defaultIfEmpty(ReactorUtils.NULL).flatMap(
                                                 nil -> {
                                                     doAfterNext(); // Execute some logic when next is completed
                                                     return Mono.empty();
                                                 }
                                         );
                                     }
                                 }
                         );
     }

     public void doSomething() {
     }

     public void doAfterNext() {
         log.info("do after next plugin done");
     }
}

Example code: https://github.com/wehotel/fizz-examples/tree/master/fizz-example-plugin/redis-auth-plugin. To run the example, please refer to the README.md.

*For the convenience of demonstration, the example does not connect to the management background, and the relevant parameters are configured in the example code. *

# manager configuration

  1. Add new plug-in definition

  1. Application plug-in

Edit route:

In RedisAuthPlugin, parameter 6 can be accessed through config.get("param6")