发布于 2026-01-06 0 阅读
0

使用 Apache APISIX API Gateway 保护 API DEV 的全球展示挑战赛,由 Mux 呈现:展示您的项目!

使用 Apache APISIX API 网关保护 API

由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!

介绍

在本教程中,我们将介绍一些用于保护Spring Boot REST API的Apache APISIX API 网关内置插件,并演示如何有效地使用它们。您将学习如何使用Docker Compose运行多容器应用程序(后端、数据库、APISIX 和 etcd一起运行)。本教程还包含有关API 安全的概念性知识,API 网关在处理横切关注点方面的重要作用,以及 Apache APISIX 如何帮助您简化和加速 API 安全保护工作。

以下是我们工作的简要概述:

✅ API 安全概述。✅
API 网关作为守门人。✅
APISIX 网关如何保护您的 API?
✅ 从 GitHub 克隆演示仓库 apisix-security-java-spring。✅
了解项目和docker-compose.yaml文件的结构。✅
通过 Docker CLI 构建多容器 APISIX。✅ 使用IP 限制
插件,仅允许白名单中的 IP 地址访问您的 API。✅使用URI 拦截插件 阻止对某些 API 资源的直接访问。✅使用消费者限制插件 ,确保只有授权用户才能请求您的 API

我们需要的关键要素:

👉 JDK 11+。请确保您的系统中已安装 OpenJDK 软件包。本演示中使用的是 Windows 操作系统和 Java 11。👉 Docker Desktop - 您还需要在本地安装 Docker Desktop 才能完成本教程。它适用于WindowsmacOS
。或者, 您也可以安装适用于 Linux 的 Docker ACI Integration CLI

💁在开始之前,让我们快速提升一下关于 API 安全和 API 网关概念的理论知识。

API 安全性概述

API 安全是指防止恶意攻击应用程序接口 (API) 的实践和产品。由于 API 已成为基于 Web 的交互编程的关键,因此也成为了黑客的目标。因此,仅需用户名和密码的基本身份验证已被各种安全方法所取代,例如多因素身份验证(MFA) 或JWT Web Token等令牌

API 安全性

在当今时代,API 安全性变得越来越重要。目前有很多加固技术可供选择:

  • TLS加密
  • API防火墙
  • 验证请求数据
  • 为保护而进行节流
  • 持续监测
  • 审计
  • 日志记录
  • IP限制
  • 还有更多。

REST API 安全是目前最常用的 API 安全机制之一。REST API 安全机制通过超文本传输​​协议 (HTTP) 统一资源标识符 (URI) 来控制 API 在运行过程中访问的数据。因此,REST API 安全机制可以有效防止攻击者利用 API 引入恶意数据。

API 网关作为守门人👮

API 网关是API 管理解决方案的重要组成部分。它对 API 安全至关重要,如同守门人一般保护底层数据,负责检查身份验证和授权,并管理流量。作为用户客户端和上游服务之间的一层薄层,API 网关还可以通过无数插件进行扩展,以处理身份验证、授权、流量控制和安全问题。

Apache APISIX是一个轻量级的开源API 网关,位于上游服务的前端。APISIX API 网关易于配置和快速部署,它作为中心点,将所有传入请求路由到其目标位置,无论是上游 API 服务器、第三方服务、数据库,甚至是无服务器平台。

APISIX 网关如何保护您的 API?

APISIX 将 API 安全性放在首位,因为它充当了对 API 进行内联控制的代理点。

  • 通过凭证和令牌验证以及其他身份验证方式,验证与 API 请求关联的身份。您可以查看可用的身份验证插件
  • 确定哪些流量被授权通过 API 发送到后端服务。
  • 通过速率限制和流量控制来控制流经 API 的流量。为此,可以使用相应的流量控制插件。
  • 监控所有请求并应用运行时策略来强制执行治理。有很多可观测性插件可以轻松地为您的 API 启用。
  • 实现了所有行业标准加密。

Apache APISIX API 网关安全性

现在我们掌握了足够的知识,可以开始在我们的 Spring Boot 演示应用中实际应用一些安全插件了。让我们开始吧🚀

克隆演示仓库

本次演示将使用我事先准备好的演示项目apisix-security-java-spring 。您可以在 Github 上查看该项目。

使用git克隆仓库:


 bash
git clone 'https://github.com/Boburmirzo/apisix-security-java-spring'


Enter fullscreen mode Exit fullscreen mode

进入apisix-security-java-spring的根目录


 bash
cd apisix-security-java-spring


Enter fullscreen mode Exit fullscreen mode

您可以使用您喜欢的代码编辑器打开该项目。我使用的是IntelliJ IDEA社区版。您会看到以下项目目录结构:

APISIX 项目目录

了解项目结构

项目文件夹中,您可以查看以下主要组件列表:

  • APISIX 的配置文件-所有服务都是通过将项目中的外部配置文件挂载到 Docker 容器中进行配置的:/apisix_conf/conf.yaml 定义了 APISIX 的配置。类似地,etcd、prometheus 和 grafana 的配置分别位于 /etcd_conf/etcd.conf.yml、/prometheus_conf/prometheus.yml 和/ grafana_conf / config
  • APISIX 的日志——位于apisix_log文件夹中,记录了 APISIX 管理和控制 API 的请求,例如access.logerror.log
  • Spring Boot 项目- 接下来,spring-postgres文件夹包含 Java 应用程序,该应用程序使用Spring 框架控制器、存储库和实体类)以及PostgreSQL 数据库设置,其中包含虚拟模式和数据。

spring-postgres 项目结构

  • Docker Compose 文件- docker-compose.yml文件定义了一个包含一些服务的应用程序:

    • apisix-dashboard- 它在 9000 端口运行APISIX Dashboard。ℹ️该 Dashboard 提供了与 APISIX Admin API 交互的另一种方式,我们可以使用 CLI 实现与 Dashboard 相同的配置结果。
    • apisix- 部署 APISIX 并将其暴露在端口上9080。在本地计算机上,您可以通过向以下 URL 发送请求来访问 APISIX 管理 API。http://127.0.0.1:9080/
    • etcd- APISIX 用于etcd保存和同步配置。
    • prometheus- APISIX 可以与prometheus 插件一起获取有关上游 API 的指标数据
    • grafana- 由 [prometheus 插件] https://apisix.apache.org/docs/apisix/plugins/prometheus导出的指标也可以在 Grafana 中绘制成图表,并且您可以在端口上看到正在运行的仪表板3000
    • backend- 在部署应用程序时,Docker Compose 会将8080后端服务容器的端口映射到8080主机的端口。
    • db- PostgreSql 数据库暴露在5432后端服务连接的端口上,后端服务从中获取数据。

☝️您可能会注意到所有服务都已映射到apisix网络。

apisix-security-java-spring项目使用了类似的APISIX docker compose 模板示例。


 yaml
version: "3"

services:
  apisix-dashboard:
    image: apache/apisix-dashboard:2.10.1-alpine
    restart: always
    volumes:
    - ./dashboard_conf/conf.yaml:/usr/local/apisix-dashboard/conf/conf.yaml
    ports:
    - "9000:9000"
    networks:
      apisix:

  apisix:
    image: apache/apisix:2.13.1-alpine
    restart: always
    volumes:
      - ./apisix_log:/usr/local/apisix/logs
      - ./apisix_conf/config.yaml:/usr/local/apisix/conf/config.yaml:ro
    depends_on:
      - etcd
    ##network_mode: host
    ports:
      - "9080:9080/tcp"
      - "9091:9091/tcp"
      - "9443:9443/tcp"
      - "9092:9092/tcp"
    networks:
      apisix:

  etcd:
    image: bitnami/etcd:3.4.15
    restart: always
    volumes:
      - etcd_data:/bitnami/etcd
    environment:
      ETCD_ENABLE_V2: "true"
      ALLOW_NONE_AUTHENTICATION: "yes"
      ETCD_ADVERTISE_CLIENT_URLS: "http://0.0.0.0:2379"
      ETCD_LISTEN_CLIENT_URLS: "http://0.0.0.0:2379"
    ports:
      - "12379:2379/tcp"
    networks:
      apisix:

  prometheus:
    image: prom/prometheus:v2.25.0
    restart: always
    volumes:
      - ./prometheus_conf/prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - "9090:9090"
    networks:
      apisix:

  grafana:
    image: grafana/grafana:7.3.7
    restart: always
    ports:
      - "3000:3000"
    volumes:
      - "./grafana_conf/provisioning:/etc/grafana/provisioning"
      - "./grafana_conf/dashboards:/var/lib/grafana/dashboards"
      - "./grafana_conf/config/grafana.ini:/etc/grafana/grafana.ini"
    networks:
      apisix:

  backend:
    build: spring-postgres/backend
    ports:
      - "8080:8080"
    environment:
      - POSTGRES_DB=example
    networks:
      apisix:

  db:
    image: postgres
    restart: always
    secrets:
      - db-password
    volumes:
      - db-data:/var/lib/postgresql/data
    networks:
      apisix:
    environment:
      - POSTGRES_DB=example
      - POSTGRES_PASSWORD_FILE=/run/secrets/db-password
    expose:
      - 5432
networks:
  apisix:
    driver: bridge
secrets:
  db-password:
    file: spring-postgres/db/password.txt
volumes:
  db-data:
  etcd_data:
    driver: local


Enter fullscreen mode Exit fullscreen mode

通过 Docker CLI 构建多容器 APISIX 环境

docker compose现在我们可以从项目根文件夹运行命令来启动应用程序:


 bash
docker-compose -p docker-apisix up -d


Enter fullscreen mode Exit fullscreen mode

示例输出:


 bash



Enter fullscreen mode Exit fullscreen mode

docker compose 运行结果

docker compose ps您可以通过运行CLI 命令或使用 Docker Desktop查看正在运行的容器列表:

在 Docker Desktop 上将 APISIX 与其他服务集成在一起

容器运行后,http://localhost:8080/get在浏览器中访问该地址,您将看到以下输出:

您好,Apache APISIX

实际上,这个响应来自简单的 Spring Boot REST API。如果您查看项目文件夹spring-postgres,会发现该src/main/java目录包含了我们项目的源代码。其中有一个GreetingController控制器类,它使用 `@Controller` 注解来处理@RestController单个端点的请求。简而言之,它从 PostgreSQL 数据库中检索数据,并使用实体类中的属性/get来响应请求nameGreeting

接下来,我们将为此端点启用不同的 Apache APISIX 安全插件。


 java
@RestController
public class GreetingController {

    private final GreetingRepository repository;

    public GreetingController(GreetingRepository repository) {
        this.repository = repository;
    }

    @GetMapping("/get")
    public String getApisixGreeting() {
        Greeting apisixGreeting = repository.findById(1).orElse(new Greeting("Not Found 😕"));
        return apisixGreeting.getName();
    }
}


Enter fullscreen mode Exit fullscreen mode

3 个 APISIX 安全插件

启用 IP 地址限制

现在我们可以为 API 端点启用IP 限制插件。IP 限制是一种通过 IP 地址白名单/黑名单机制来限制可以发送请求的客户端 IP 地址的技术。我们将无法使用除允许的 IP 地址之外的 IP 地址访问 API。

第一步,我们需要为后端服务创建一个上游。我们使用curl命令与 APISIX 的管理 API 进行交互:


 bash
curl "http://127.0.0.1:9080/apisix/admin/upstreams/1" -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -X PUT -d '
{
  "type": "roundrobin",
  "nodes": {
    "backend:8080": 1
  }
}'


Enter fullscreen mode Exit fullscreen mode

上游对象将指向目标backend服务或多个后端服务,在本例中,它引用的是 Spring Boot REST API。

下一步,我们将定义一条路由并将其绑定到上游。它可以映射到upstream_id特定的路由。此外,我们还将ip-restriction在路由配置中启用插件。


 bash
curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
    "uri": "/get",
    "plugins": {
       "ip-restriction": {
            "whitelist": [
                "127.0.0.2"
            ]
        }
    },
    "upstream_id": "1"
}'


Enter fullscreen mode Exit fullscreen mode

在插件whitelist属性中ip-restriction,我们只允许单个 IP 地址127.0.0.2访问/getURI。如果您尝试使用被禁止的 IP 地址访问 API,APISIX 将抛出 403 Forbidden HTTP 错误:


 bash
curl http://127.0.0.1:9080/get -i --interface 127.0.0.1


Enter fullscreen mode Exit fullscreen mode

示例输出:


 text
HTTP/1.1 403 Forbidden
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX/2.13.1

{"message":"Your IP address is not allowed"}


Enter fullscreen mode Exit fullscreen mode

☝️ 插件配置中可以使用单个 IP 地址、多个 IP 地址或 CIDR 表示法的地址范围(例如 10.10.10.0/24)。该插件还支持 IPv4 和 IPv6 地址。

现在我们知道了一种方法,即通过使用 APISIX 来允许/禁止 IP 地址,从而保护我们的 API。

阻止对 API 资源的直接访问

接下来,我们将通过应用正则表达式过滤规则,使用uri-blocker 插件来了解更强大的 URI 拦截功能。例如,当用户尝试访问和下载私有文件时,我们可能需要拦截该 API 端点sample-file.csv

我们可以启用uri-blocker类似于ip-restriction上一步中应用的插件配置的插件:


 bash
curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
    "uri": "/*",
    "plugins": {
       "uri-blocker": {
          "block_rules": ["sample-file.csv+"]
        }
    },
    "upstream_id": "1"
}'


Enter fullscreen mode Exit fullscreen mode

按照上述步骤配置好插件后,您可以使用以下curl命令尝试访问该文件:



curl -i http://127.0.0.1:9080/sample-file.csv


Enter fullscreen mode Exit fullscreen mode

你应该会收到另一个 HTTP 403 禁止访问错误:


 text
HTTP/1.1 403 Forbidden


Enter fullscreen mode Exit fullscreen mode

现在我们限制了对 URI 资源的直接访问。您还可以设置rejected_msg插件配置属性来自定义响应正文消息

允许用户请求 API

其中一种方法是针对特定用户或服务设置相应的 API 资源访问限制。消费者限制consumer-restriction)会根据选定的不同用户,对您的服务或路由设置相应的访问限制。如果未知用户尝试发送请求,Apache APISIX 将返回错误。

假设我们有两个 API 使用者(Aconsumer1和 B consumer2)。我们只想向其中一个使用者授予访问权限。为此,让我们创建两个使用者,并consumer-restriction为现有的示例路由启用插件。

要创建第一个消费者,请运行以下命令:


 bash
curl http://127.0.0.1:9080/apisix/admin/consumers -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -i -d '
{
    "username": "consumer1",
    "plugins": {
        "basic-auth": {
            "username":"consumer1",
            "password": "123456"
        }
    }
}'


Enter fullscreen mode Exit fullscreen mode

要创建第二个消费者,请运行以下命令:


 bash
curl http://127.0.0.1:9080/apisix/admin/consumers -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -i -d '
{
    "username": "consumer2",
    "plugins": {
        "basic-auth": {
            "username":"consumer2",
            "password": "654321"
        }
    }
}'


Enter fullscreen mode Exit fullscreen mode

然后,启用consumer-restriction插件并仅允许consumer1访问该/get端点:



curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
    "uri": "/get",
    "plugins": {
        "basic-auth": {},
        "consumer-restriction": {
            "whitelist": [
                "consumer1"
            ]
        }
    },
    "upstream_id": "1"
}'


Enter fullscreen mode Exit fullscreen mode

consumer-restriction具有 type 属性,该属性是枚举类型(支持以下值:consumer_name、service_idroute_id),我们可以指定它以允许访问相应的对象。

{"message":"The consumer_name is forbidden."}默认情况下,如果对象不允许,插件会返回一个通用错误信息。您可以通过插件属性配置更友好的错误信息。

现在我们可以测试消费者是否consumer1能够使用提供的凭据请求 API 资源:


 bash
curl -u consumer1:123456 http://127.0.0.1:9080/get -i


Enter fullscreen mode Exit fullscreen mode

输出:


 text
HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 19
Connection: keep-alive
Server: APISIX/2.13.1

Hello Apache APISIX


Enter fullscreen mode Exit fullscreen mode

很明显,它consumer1可以请求该端点,因为我们在插件配置中将消费者列入了白名单consumer-restriction

然而,我们的第二个消费者没有访问权限。现在我们可以尝试使用不同的消费者凭证请求相同的路径:


 bash
curl -u consumer2:123456 http://127.0.0.1:9080/get -i


Enter fullscreen mode Exit fullscreen mode

输出:


text
HTTP/1.1 403 Forbidden
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX/2.13.1

{"message":"The consumer_name is forbidden."}

Enter fullscreen mode Exit fullscreen mode




接下来会发生什么?

在本篇博文中,我们演示了如何利用 Docker Compose 功能,将 Spring Boot REST API 应用与 Apache APISIX API 网关集成部署,从而实现更流畅的部署。此外,我们还学习了如何使用基本的安全插件,您可以查看其他可用的插件以满足更高级的 API 安全需求,或者借助Java Plugin Runner为 API 网关创建自定义插件。

推荐内容

➔观看视频教程:Apache APISIX入门

➔ 阅读博文《Apache APISIX API 网关插件概述》

➔ 阅读博文《使用 Apache APISIX 插件实现集中式身份验证》

➔ 阅读博文《使用 Apache APISIX 和 Microsoft Azure AD 通过 OIDC 实现 API 安全》

➔ 阅读博文《使用 Apache APISIX 插件实现 API 可观测性》

社区⤵️

🙋加入 Apache APISIX 社区
🐦在 Twitter 上关注我们
📝在 Slack 上找到我们
📧给我们发送邮件提出您的问题

文章来源:https://dev.to/apisix/secure-spring-boot-rest-api-with-apache-apisix-api-gateway-1nmg