1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

jsonのフィールドをvalidateするGatewayFilterFactoryを作ってみた

Last updated at Posted at 2020-12-02

概要

  • SpringCloudGatewayでRequestBodyをいじってみるついでにjsonのフィールドをvalidateするGatewayFilterFactoryを作ってみた
  • 名付けてValidateRequestBodyGatewayFilterFactory!!(笑)

できること/制約

  • フィールドに対して指定した正規表現を満たすかチェックできる
  • 指定されていないフィールドを落とせる
  • 多階層のjsonには対応していない
  • 数値が文字列でバックポストされる("value":123 → "value":"123")

作ったもの

SpringCloudGatewayに用意されているModifyRequestBodyGatewayFilterFactoryを参考にしました

ValidateRequestBodyGatewayFilterFactory
@Component
public class ValidateRequestBodyGatewayFilterFactory extends AbstractGatewayFilterFactory<ValidateRequestBodyGatewayFilterFactory.Config> {
    public ValidateRequestBodyGatewayFilterFactory() {
        super(Config.class);
    }

    private final List<HttpMessageReader<?>> messageReaders = HandlerStrategies.withDefaults().messageReaders();

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            var serverRequest = ServerRequest.create(exchange, messageReaders);
            var validatedBody = serverRequest.bodyToMono(StringMap.class)
                    .map(originalBody -> {
                        var verifiedParams = new StringMap();
                        for (var key: originalBody.keySet()) {
                            var pattern = config.getPattern(key);
                            if (pattern != null) {
                                var param = originalBody.get(key);
                                if (pattern.matcher(param).find()) {
                                    verifiedParams.put(key, param);
                                }
                            }
                        }

                        return verifiedParams;
                    });

            HttpHeaders headers = new HttpHeaders();
            headers.putAll(exchange.getRequest().getHeaders());
            headers.remove(HttpHeaders.CONTENT_LENGTH);

            CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(
                    exchange, headers);

            BodyInserter bodyInserter = BodyInserters.fromPublisher(validatedBody, StringMap.class);
            return bodyInserter.insert(outputMessage, new BodyInserterContext())
                    .then(Mono.defer(() -> {
                        var decorator = new ServerHttpRequestDecorator(exchange.getRequest()) {
                            @Override
                            public Flux<DataBuffer> getBody() {
                                return outputMessage.getBody();
                            }

                            @Override
                            public HttpHeaders getHeaders() {
                                return headers;
                            }
                        };

                        return chain.filter(exchange.mutate().request(decorator).build());
                    }));
        };
    }

    @Getter
    public static class Config {
        private Map<String, Pattern> roles = new HashMap<>();

        public void setRoles(String role) {
            try {
                Map<String, String> originalRoles = new ObjectMapper().readValue(role, StringMap.class);
                for (var key: originalRoles.keySet()) {
                    this.roles.put(key, Pattern.compile(originalRoles.get(key)));
                }
            } catch (Exception ex) {
                throw new IllegalArgumentException(ex);
            }
        }

        public Pattern getPattern(String key) {
            return this.roles.getOrDefault(key, null);
        }
    }

    public static class StringMap extends HashMap<String, String> { }
}

使い方

application.yml
spring:
  cloud:
    gateway:
      routes:
        - id: validate
          uri: <バックポスト先>
          filters:
            - name: ValidateRequestBody
              args:
                # jsonで「フィールド:正規表現」の組み合わせを定義する 
                roles: |
                  {"number":"^[0-9]+$"}

この設定だと

{"number":123,"hoge":"hoge"}
↓
{"number":"123"}

のようにnumberだけが透過する

何かの役に立つ時が来たらいいな😇

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?