Spring Boot

springboot webflux 过滤器中识别自定义注解校验

2021-03-24  本文已影响0人  itkkanae

在WebFilter中识别web接口上添加的自定义注解:

Controller的接口如下(@Token是自己建立的注解):

    @Token
    @GetMapping("/test")
    public Mono<String> test() {
        return Mono.just("success");
    }

WebFilter代码:

import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.MultiValueMap;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;


@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public class TokenFilter implements WebFilter {

    @Resource
    private RequestMappingHandlerMapping requestMappingHandlerMapping;

    private boolean flag;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        ServerHttpResponse res = exchange.getResponse();
        ServerHttpRequest req = exchange.getRequest();

        // 获取请求对应的HandlerMethod
        Mono<HandlerMethod> handlerMethodMono = requestMappingHandlerMapping
                .getHandler(exchange).cast(HandlerMethod.class);

        return handlerMethodMono.zipWhen(handlerMethod -> {
            // 判断Method是否含有对应注解
            if (handlerMethod.hasMethodAnnotation(Token.class)) {

                MultiValueMap<String, String> params = req.getQueryParams();
                HttpHeaders headers = req.getHeaders();
                // 从参数中获取token
                String token = params.getFirst("token");
                // 从header获取token
                token = headers.getFirst("token");
                // TODO: 校验Token

                boolean valid = true;
                // 校验通过,过滤器正常放行
                if (valid) return chain.filter(exchange);

            }

            // TODO: 校验不通过,返回错误信息
            res.setStatusCode(HttpStatus.NON_AUTHORITATIVE_INFORMATION);
            byte[] bytes = "NON_AUTHORITATIVE_INFORMATION".getBytes();
            return res.writeWith(Mono.just(res.bufferFactory().wrap(bytes)));

        }).map(Tuple2::getT2);
    }

}

一些可能不用在意的点:
1、Token.class改成自己对应的注解

flag = handlerMethod.hasMethodAnnotation(Token.class);

2、设置状态码不是必须的,但这是个枚举型,里面可能没有一些你想要的奇怪值

res.setStatusCode(HttpStatus.NON_AUTHORITATIVE_INFORMATION);

3、自定义的返回内容要转成byte数组

byte[] bytes = "NON_AUTHORITATIVE_INFORMATION".getBytes();
return res.writeWith(Mono.just(res.bufferFactory().wrap(bytes)));

4、你需要的请求参数可以从这儿取

MultiValueMap<String, String> params = req.getQueryParams();
HttpHeaders headers = req.getHeaders();

5、Debug了几遍,RequestMappingHandlerMapping的beanName是requestMappingHandlerMapping,他记录了所有接口地址和对应方法

@Resource
private RequestMappingHandlerMapping requestMappingHandlerMapping;

6、springboot版本

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.4.4</version>
    <relativePath/>
</parent>
上一篇下一篇

猜你喜欢

热点阅读