gateway调用feign

文章目录

  • 前言
  • gateway简介及与springboot的区别
  • 项目配置
    • 微服务配置
      • 接口配置
      • feign接口
      • 配置feign配置
    • gateway配置
  • 总结
  • 源码地址
  • Q&A

前言

        在搭建项目的时候,需要网关去校验请求的合法性。这里通过gateway的filter中通过调用feign接口去验证token的方式实现。

gateway简介及与springboot的区别

todo

项目配置

微服务配置

接口配置

在微服务中,只展示controller的代码,其他的自己实现就可以。

  @ApiOperationSupport(order = 90, author = "alex")
    @ApiOperation(value = "根据token校验用户权限", notes = "根据token校验用户权限", response = Result.class)
    @GetMapping(value = "/authToken")
    @ApiImplicitParams({
            @ApiImplicitParam(value = "token", name = "token")}
    )
    public Result authToken(@RequestParam(value = "token") String token) {
        return Result.success(true) ;
    }

feign接口

在这里根据spring.profiles.active动态去配置服务名,方便区分测试环境和正式环境。

@Component
@FeignClient(name = "alex-user-${spring.profiles.active:dev}", fallback = UserFallbackFactory.class, configuration = FeignConfig.class)
public interface UserApi {

    @GetMapping(value = "/api/v1/user/authToken")
    Result authToken(@RequestParam("token") String token);
}

feign异常处理类。

@Component
@Slf4j
public class UserFallbackFactory implements FallbackFactory {

    @Override
    public UserApi create(Throwable cause) {
        throw new SystemException(ResultEnum.SYSTEM_NO_AVAILABLE, "user");
    }
}

配置feign配置

@Configuration
public class FeignConfig implements RequestInterceptor {

    @Override
    public void apply(RequestTemplate requestTemplate) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            //添加token
            requestTemplate.header("Authorization", request.getHeader("Authorization"));
        }
    }

    @Bean
    public Logger.Level level() {
        //仅记录请求方法、URL、响应状态代码以及执行时间,生成一般用这个
        return Logger.Level.BASIC;
    }

    @Bean
    public RequestContextListener requestContextListener(){
        return new RequestContextListener();
    }
}

gateway配置

在GatewayApplication中配置EnableFeignClients调用feign。

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableDiscoveryClient
@ComponentScan(basePackages = {"com.alex.gateway", "com.alex.common", "com.alex.api.user"})
@EnableFeignClients(basePackages = {"com.alex.api.user"})
public class GatewayApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(GatewayApplication.class, args);
        AutowiredBean.setApplicationContext(run);
    }
}
@Component
@Slf4j
@RequiredArgsConstructor
public class GatewayFilter implements GlobalFilter, Ordered {

    private final GatewayAudience audience;

    private static final PathMatcher antPathMatcher = new AntPathMatcher();

    @SneakyThrows
    @Override
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String path = exchange.getRequest().getPath().toString();
        //白名单校验路径
        if (audience.getWhiteList() != null && !audience.getWhiteList().isEmpty()) {
            for (String white : audience.getWhiteList()) {
                if (antPathMatcher.match(white, path)) {
                    return chain.filter(exchange);
                }
            }
        }
        log.info("当前请求地址:{}", path);
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        Map attributes1 = exchange.getAttributes();
        //得到请求头信息authorization信息
        String token = Optional.ofNullable(request)
                .map(re -> re.getHeaders())
                .map(header -> header.getFirst(audience.getTokenHeader()))
                .orElse(null);
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
        UserApi userApi = AutowiredBean.getBean(UserApi.class);
        CompletableFuture> completableFuture = CompletableFuture.supplyAsync(() -> {
                    // 复制主线程的 线程共享数据
                    RequestContextHolder.setRequestAttributes(attributes);
                    Result res = userApi.authToken(token);
                    return res;
                }
        );
        Boolean result = Optional.ofNullable(completableFuture).map(item -> {
            try {
                return item.get().getData();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } catch (ExecutionException e) {
                throw new RuntimeException(e);
            }
        }).get();
        if (result) {
            return chain.filter(exchange);
        }
        return out(response);
    }

    /**
     * @description: 拦截器的优先级,数字越小优先级越高
     * @author: majf
     * @return: int
     */
    @Override
    public int getOrder() {
        return 0;
    }

    private Mono out(ServerHttpResponse response) {
        JsonObject message = new JsonObject();
        message.addProperty("success", false);
        message.addProperty("code", 403);
        message.addProperty("data", "请先登录!");
        byte[] bits = message.toString().getBytes(StandardCharsets.UTF_8);
        DataBuffer buffer = response.bufferFactory().wrap(bits);
        //response.setStatusCode(HttpStatus.UNAUTHORIZED);
        //指定编码,否则在浏览器中会中文乱码
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        return response.writeWith(Mono.just(buffer));
    }
}
public class AutowiredBean {

    private static ApplicationContext applicationContext;

    public static void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (AutowiredBean.applicationContext == null) {
            AutowiredBean.applicationContext = applicationContext;
        }
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }

    public static  T getBean(Class clazz) {
        return getApplicationContext().getBean(clazz);
    }

    public static  T getBean(String name, Class clazz) {
        return getApplicationContext().getBean(name, clazz);
    }
}

总结

至此在网关中调用feign接口配置完成。

源码地址

地址

Q&A

todo

你可能感兴趣的:(项目搭建,java,gateway,java,spring)