gateway调用feign

该文介绍了如何在项目中利用SpringCloudGateway作为网关进行请求合法性校验,通过Gateway的Filter调用Feign接口验证token。文中详细展示了从微服务配置、接口定义、Feign客户端配置到Gateway的Filter实现的整个流程,旨在实现基于token的用户权限校验。
摘要由CSDN通过智能技术生成

前言

        在搭建项目的时候,需要网关去校验请求的合法性。这里通过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<Boolean> 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<Boolean> authToken(@RequestParam("token") String token);
}

feign异常处理类。

@Component
@Slf4j
public class UserFallbackFactory implements FallbackFactory<UserApi> {

    @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<Void> 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<String, Object> 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<Result<Boolean>> completableFuture = CompletableFuture.supplyAsync(() -> {
                    // 复制主线程的 线程共享数据
                    RequestContextHolder.setRequestAttributes(attributes);
                    Result<Boolean> 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<Void> 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> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }

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

总结

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

源码地址

地址

Q&A

todo

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值