前景:限制fegin接口只能内部调用不允许通过网关调用
思路:
借助接口路径规范来实现,即给接口指定访问路径时采用这样的格式 : /访问控制/接口。
1、定义fegin统一前缀
/**
* @description: 所有fegin接口需要加前缀 禁止外部调用
* @author: loren
* @Description: TODO
* @create: 2023-03-14 19:25
**/
public class PrefixPath {
/**
* 所有fegin接口前缀
*/
public static final String FEGIN_PATH_PREFIX = "/fegin";
}
2、fegin接口提供者加上前缀(消费者需要和提供者接口地址保持一致的这里不做过多解释)
提供者:
@ApiOperation(value = "测试fegin接口",notes = "测试fegin接口")
@GetMapping(PrefixPath.FEGIN_PATH_PREFIX +"/user/testFegin")
public TestFeginUser testFeginUser(String name){
TestFeginUser testFeginUser = new TestFeginUser(name,18);
return testFeginUser;
}
fegin接口定义:
@FeignClient(name = "user",fallback = FeignClientFallback.class)
public interface UserFeginClient {
/**
* 测试feign接口
* @param name
* @return
*/
@GetMapping(PrefixPath.FEGIN_PATH_PREFIX +"/user/testFegin")
TestFeginUser testFeginUser(@RequestParam("name") String name);
}
调用方:
@ApiOperation(value = "Test",notes = "Test")
@GetMapping("/test/testfegin")
public HyResponse testfegin(String name) throws NacosException {
TestFeginUser testFeginUser = userFeginInterFace.testFeginUser(name);
return HyResponse.success(testFeginUser);
}
gateway 全局过滤器拦截
@Slf4j
@RefreshScope
@Configuration
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class PubGlobalFilter {
/**
* 打印请求日志
* @return
*/
@Bean
@Order(1)
public GlobalFilter logGlobalFilter(){
return (exchange, chain) -> {
String rawPath = exchange.getRequest().getURI().getRawPath();
log.info("gateway--path--log:{}",rawPath);
//获取请求路径
if(isPv(rawPath)){
throw new HttpServerErrorException(HttpStatus.FORBIDDEN,"prohibit external access to the fegin API");
}
// 继续向下执行
return chain.filter(exchange);
};
}
/**
* 判断是否内部私有方法
* @param requestURI 请求路径
* @return boolean
*/
private boolean isPv(String requestURI) {
return isAccess(requestURI,"/fegin");
}
/**
* 网关访问控制校验
*/
private boolean isAccess(String requestURI, String access) {
//后端标准请求路径为 /访问控制/请求路径
int index = requestURI.indexOf(access);
return index >= 0 && StringUtils.countOccurrencesOf(requestURI.substring(0,index),"/") < 1;
}
}
网关错误拦截:
@Slf4j
@Order(-1)
@Configuration
@RequiredArgsConstructor
public class GlobalExceptionConfiguration implements ErrorWebExceptionHandler {
private final ObjectMapper objectMapper;
@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
ServerHttpResponse response = exchange.getResponse();
if (response.isCommitted()) {
return Mono.error(ex);
}
// header set
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
if (ex instanceof ResponseStatusException) {
response.setStatusCode(((ResponseStatusException) ex).getStatus());
}
return response
.writeWith(Mono.fromSupplier(() -> {
DataBufferFactory bufferFactory = response.bufferFactory();
try {
log.error("网关错误,请重试: {}", ex.getMessage());
return bufferFactory.wrap(objectMapper.writeValueAsBytes(HyResponse.of(BizCode.COMMON_GATEWAY_TIME_OUT.getCode(),false,"gateway timeout, please try again", StringUtils.isNotBlank(ex.getMessage())?ex.getMessage():BizCode.COMMON_GATEWAY_TIME_OUT.getMessage())));
} catch (JsonProcessingException e) {
log.warn("Error writing response", ex);
return bufferFactory.wrap(new byte[0]);
}
}));
}
}
调用结果: