保护 WebSocket 流量
WebSocket 是一种广泛使用的协议,旨在通过单个 TCP 连接促进客户端和服务器之间的实时双向通信。与传统的 HTTP 不同,WebSocket 实现了持久通信,允许数据在两个方向上无缝流动,而无需重复 HTTP 请求的开销。这使其非常适合需要低延迟数据交换的应用程序,例如实时聊天、协作工具、多人游戏和其他交互式平台。
WebSocket 对于实时通信很有效,但它有一个局限性:它不支持在 HTTP 握 手期间设置自定义标头,包括常用的 Authorization 标头。当保护 WebSocket 连接时,这带来了一个挑战,因为协议本身缺乏内置的身份验证机制。如果没有适当的保护措施,WebSocket 端点可能会容易受到未经授权的访问和滥用。
APISIX 通过在初始握手期间启用身份验证机制来解决 WebSocket 流量的这一缺口。在本指南中,你将了解如何配置 APISIX 以验证和代理 WebSocket 连接。
前置条件
- 安装 Docker。
- 安装 cURL 以向服务发送请求进行验证。
- 安装 websocat 以建立与 WebSocket 服务器的 WebSocket 连接。
- 按照 快速入门教程 在 Docker 或 Kubernetes 中启动一个新的 APISIX 实例。
启动 WebSocket 示例服务器
启动一个支持 WebSocket 的 示例上游服务器。
- Docker
- Kubernetes
docker run -d \
-p 8080:8080 \
--name websocket-server \
--network=apisix-quickstart-net \
jmalloc/echo-server
为部署 WebSocket 服务器创建一个 Kubernetes 清单文件:
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: ingress-apisix
name: websocket-server
spec:
replicas: 1
selector:
matchLabels:
app: websocket-server
template:
metadata:
namespace: ingress-apisix
labels:
app: websocket-server
spec:
containers:
- name: echo-server
image: jmalloc/echo-server
ports:
- containerPort: 8080
为 WebSocket 服务创建另一个 Kubernetes 清单文件:
apiVersion: v1
kind: Service
metadata:
namespace: ingress-apisix
name: websocket-server
spec:
selector:
app: websocket-server
ports:
- protocol: TCP
port: 8080
targetPort: 8080
type: ClusterIP
将配置应用到你的集群:
kubectl apply -f ws-deployment.yaml -f ws-service.yaml
该服务器在 /.ws 处有一个 WebSocket 端点,它会回显收到的任何消息。
创建路由
创建一个指向示例上游服务器的路由,并启用 WebSocket 和 key-auth 插件。你也可以使用其他身份验证插件。
- Admin API
- ADC
- Ingress Controller
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT -d '
{
"id": "ws-route",
"uri": "/.ws",
"enable_websocket": true,
"plugins": {
"key-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"websocket-server:8080": 1
}
}
}'
services:
- name: websocket Service
routes:
- uris:
- /.ws
name: ws-route
enable_websocket: true
plugins:
key-auth: {}
upstream:
type: roundrobin
nodes:
- host: websocket-server:8080
port: 8080
weight: 1
将配置同步到 APISIX:
adc sync -f route.yaml
- Gateway API
- APISIX CRD
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: ingress-apisix
name: auth-plugin-config
spec:
plugins:
- name: key-auth
config:
_meta:
disable: false
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: ingress-apisix
name: ws-route
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /.ws
filters:
- type: ExtensionRef
extensionRef:
group: apisix.apache.org
kind: PluginConfig
name: auth-plugin-config
backendRefs:
- name: websocket-server
port: 8080
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: ingress-apisix
name: ws-route
spec:
ingressClassName: apisix
http:
- name: ws-route
match:
paths:
- /.ws
websocket: true
backends:
- serviceName: websocket-server
servicePort: 8080
plugins:
- name: key-auth
enable: true
将配置应用到你的集群:
kubectl apply -f ws-route.yaml
创建消费者
至少创建一个消费者及其凭证。
- Admin API
- ADC
- Ingress Controller
创建消费者 john:
curl -i "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT -d '
{
"username": "john"
}'
为 john 配置 key-auth 凭证:
curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT -d '
{
"id": "cred-john-key-auth",
"plugins": {
"key-auth": {
"key": "john-key"
}
}
}'
创建消费者 john 并配置其 key-auth 凭证:
consumers:
- username: john
credentials:
- name: john-key
type: key-auth
config:
key: john-key
将配置同步到 APISIX:
adc sync -f route.yaml -f consumer.yaml
创建消费者 john 并配置其 key-auth 凭证:
- Gateway API
- APISIX CRD
apiVersion: apisix.apache.org/v1alpha1
kind: Consumer
metadata:
namespace: ingress-apisix
name: john
spec:
gatewayRef:
name: apisix
credentials:
- type: key-auth
name: john-key
config:
key: john-key
apiVersion: apisix.apache.org/v2
kind: ApisixConsumer
metadata:
namespace: ingress-apisix
name: john
spec:
ingressClassName: apisix
authParameter:
keyAuth:
value:
key: john-key
将配置应用到你的集群:
kubectl apply -f consumer.yaml
验证连接
通过路由与 WebSocket 服务器建立连接,不带任何凭证:
websocat "ws://127.0.0.1:9080/.ws"
你应该看到 401 Unauthorized 响应。
使用 john 的凭证通过路由与 WebSocket 服务器建立连接:
websocat "ws://127.0.0.1:9080/.ws" -H 'apikey: john-key'
你 应该看到服务器已准备好为传入请求提供服务。在终端中发送一条 "hello" 消息。你应该看到 WebSocket 服务器回显相同的消息:
Request served by 510852d98edc
hello
hello
你可以继续发送更多消息,WebSocket 服务器将回显你发送的任何消息。这表明双向连接已成功并持久。
下一步
你现在已经了解了如何使用 APISIX 验证和代理 WebSocket 连接。如果你想限制 WebSocket 连接的数量,请参阅 limit-conn 插件文档以了解更多信息。