最近也是在学习webflux框架,学一点就记录一下,今天的这个问题其实在传统的spring的框架中很简单,直接在过滤器中拦截就可以了,其实在webflux响应框架中也是类似,以下是我的两种实现方式
方式1: 实现一个webFilter拦截器,在filter里面实现拦截,这里是仿照org.springframework.web.reactive.DispatcherHandler#handle方法来实现的
@Slf4j
@Component
public class LoginFilter implements WebFilter {
@Autowired
private LoginService loginService;
@Autowired
private ApplicationContext context;
@Nullable
private List<HandlerMapping> handlerMappings;
private final DataBufferFactory dataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
return Flux.fromIterable(handlerMappings)
.concatMap(mapping -> mapping.getHandler(exchange))
.next()
.switchIfEmpty(Mono.defer((Supplier<Mono<?>>) () -> Mono.just(createResult("找不到资源"))))
.flatMap(handler -> {
// 资源,直接跳过
if (handler instanceof ResourceWebHandler) {
return chain.filter(exchange);
}
// 剩下的全判断是否需要登录
boolean isLogin = isLogin(handler);
if (!isLogin){
return chain.filter(exchange);
}
if (checkToken(exchange)) {
return chain.filter(exchange);
}
exchange.getResponse().getHeaders().add("Content-Type", "application/json");
Publisher<? extends DataBuffer> just = Mono.just(dataBufferFactory.wrap(createResult("未登录").getBytes()));
return new ChannelSendOperator<>(just, body -> exchange.getResponse().writeWith(body));
});
}
/**
* 判断是否需要登录
*
* @param handler
* @return
*/
private boolean isLogin(Object handler) {
if (handler instanceof HandlerMethod) {
// 这里通过自定义注解来判断是否需要登录,NoLogin为我的自定义注解
NoLogin annotation = ((HandlerMethod) handler).getMethod().getAnnotation(NoLogin.class);
return annotation == null;
}
return true;
}
@PostConstruct
protected void initStrategies() {
Map<String, HandlerMapping> mappingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerMapping.class, true, false);
ArrayList<HandlerMapping> mappings = new ArrayList<>(mappingBeans.values());
AnnotationAwareOrderComparator.sort(mappings);
this.handlerMappings = Collections.unmodifiableList(mappings);
}
private boolean checkToken(ServerWebExchange exchange) {
final ServerHttpRequest request = exchange.getRequest();
HttpHeaders headers = request.getHeaders();
String token = headers.getFirst("token");
if (token == null) {
return false;
}
// 自己的校验token逻辑
UserBean userBean = loginService.checkToken(token);
if (userBean == null) {
return false;
}
return true;
}
private String createResult(String errorMsg) {
BaseResult result = new BaseResult();
result.setMsg(errorMsg);
result.setCode(999);
return JSONObject.toJSONString(result);
}
}
方式2 继承RequestMappingHandlerAdapter方法,然后通过WebFluxRegistrations注入到springWebflux中
@Slf4j
public class XRequestMappingHandlerAdapter extends RequestMappingHandlerAdapter {
@Autowired
private LoginService loginService;
@Override
public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
boolean isLogin = isLogin(handler);
if (!isLogin){
return super.handle(exchange, handler);
}
if (checkToken(exchange)) {
return super.handle(exchange, handler);
}
log.info("{}不存在token,且未登录:{}", exchange.getLogPrefix(), exchange.getRequest().getPath().value());
return Mono.just(new HandlerResult(handler, Mono.just(new BaseResult(999, "未登录")),
new MethodParameter(((HandlerMethod) handler).getMethod(), -1)));
}
/**
* 根据注解判断是否需要登录
*
* @param handler
* @return
*/
private boolean isLogin(Object handler) {
if (handler instanceof HandlerMethod) {
NoLogin annotation = ((HandlerMethod) handler).getMethod().getAnnotation(NoLogin.class);
return annotation == null;
}
return true;
}
/**
* 校验token是否有效
*
* @param exchange
* @return
*/
private boolean checkToken(ServerWebExchange exchange) {
final ServerHttpRequest request = exchange.getRequest();
HttpHeaders headers = request.getHeaders();
String token = headers.getFirst("token");
// 获取token
if (token == null) {
return false;
}
// 校验token
UserBean userBean = loginService.checkToken(token);
if (userBean == null) {
return false;
}
return true;
}
}
// 通过实现WebFluxRegistrations 接口注入RequestMappingHandlerAdapter
@Slf4j
@Component
public class XWebFluxRegistrations implements WebFluxRegistrations {
@Override
public RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() {
return new XRequestMappingHandlerAdapter();
}
}
以上就是两种拦截并校验token的方式,
方式1,可以拦截多种请求,如资源文件,RequestMapping,或者RouterFunctionMapping,这些都可以拦截。
方式2只能拦截RequestMapping的
如有更好的实现,欢迎交流
如果有用,麻烦动动小手点个赞 ?
版权声明:本文为weixin_38390086原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。