單頁 React 應用程式(含 OAuth)
此沙箱提供使用 Envoy 建置和開發單頁應用程式的範例。
此沙箱涵蓋多項 Envoy 的功能,包括
動態 xDS 檔案系統更新
Websocket 代理
Gzip 壓縮
TLS/SNI 上/下游連線/終止
路徑/主機重寫
此應用程式使用 React,並使用 Vite 建置,並示範使用 Envoy 的 OAuth 篩選器 進行 OAuth 驗證。
這涵蓋了我們希望 OAuth 同時驗證使用者並提供憑證以進行進一步 API 互動的情況。
藉由將 OAuth 設定 forward_bearer_token 設定為 true
來啟用此功能。
36 redirect_uri: "%REQ(x-forwarded-proto)%://%REQ(:authority)%/authorize"
37 forward_bearer_token: true
38 pass_through_matcher:
39 name: ":path"
40 string_match:
警告
設定 forward_bearer_token 表示提供的存取權杖將會轉送到此 HTTP 篩選器鏈的 Envoy 代理的任何叢集/上游。
如果存在不受信任的上游,則需要小心移除任何敏感的 Cookie,例如 BearerToken
。
可以藉由針對受影響的路由設定 request_headers_to_remove 來達成此目的。
隨附提供了一個虛擬「Myhub」後端,其中包含一個最基本的 OAuth 提供者和 API,以供範例中使用。
隨附提供了建置和更新應用程式以供生產使用的設定,以及具有自動程式碼重新載入功能的開發環境。
生產和開發環境分別在連接埠 10000
和 10001
上公開。
Myhub 後端可以輕鬆地替換為 Github 或其他基於 OAuth 的上游服務,並且隨附提供了一些關於如何執行此操作的指引。
步驟 1:建立一個 .local
目錄以進行沙箱自訂
變更為 examples/single-page-app
目錄,並建立一個目錄來儲存沙箱自訂。
您可以使用 Git 會忽略的 .local
$ mkdir .local
將 ui/
目錄複製到 .local
並設定 UI_PATH
。這樣將可以在不變更已提交檔案的情況下進行自訂。
$ cp -a ui .local
$ export UI_PATH=./.local/ui
步驟 2:產生 HMAC 金鑰
Envoy 的 OAuth 篩選器 需要 HMAC 金鑰來編碼憑證。
將預設的沙箱金鑰複製到自訂目錄,並建立所需的 HMAC 金鑰。
將 MY_HMAC_SECRET_SEED
替換為您選擇的詞組
$ cp -a secrets .local
$ HMAC_SECRET=$(echo "MY_HMAC_SECRET_SEED" | mkpasswd -s)
$ export HMAC_SECRET
$ envsubst < hmac-secret.tmpl.yml > .local/secrets/hmac-secret.yml
為 Docker 匯出金鑰資料夾的路徑
$ export SECRETS_PATH=./.local/secrets
步驟 3:啟動容器
首先匯出 UID
,以確保使用您的使用者 ID 建立容器建立的檔案。
然後啟動 Docker 編排
$ pwd
envoy/examples/single-page-app
$ export UID
$ docker compose pull
$ docker compose up --build -d
$ docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
single-page-app-envoy-1 single-page-app-envoy "/docker-entrypoint.sh envoy -c /etc/envoy/envoy.yaml ..." envoy 2 minutes ago Up 2 minutes 0.0.0.0:10000-10001->10000-10001/tcp, :::10000-10001->10000-10001/tcp
single-page-app-myhub-1 single-page-app-myhub "/opt/myhub/app.py" myhub 2 minutes ago Up 2 minutes (healthy) 0.0.0.0:7000->7000/tcp, :::7000->7000/tcp
single-page-app-myhub-api-1 single-page-app-myhub-api "/opt/myhub/app.py" myhub-api 2 minutes ago Up 2 minutes (healthy)
single-page-app-ui-1 single-page-app-ui "/entrypoint.sh dev.sh" ui 2 minutes ago Up 2 minutes (healthy)
步驟 4:瀏覽至開發應用程式並登入
開發應用程式現在應該可在 https://127.0.0.1:10001 上使用,並提供登入按鈕

注意
虛擬 OAuth 提供者自動信任所有人為硬式編碼的 envoydemo
使用者,並重新導向回應用程式。
在實際情況下,提供者會在繼續之前驗證和授權使用者。
沙箱設定為對 pass_through_matcher 進行反轉比對。
這會忽略 OAuth 的所有路徑,但以下路徑除外
/authorize.*
/hub.*
/login
/logout
.
37 forward_bearer_token: true
38 pass_through_matcher:
39 name: ":path"
40 string_match:
41 safe_regex:
42 regex: >-
43 ^\/(authorize.*|login|logout)$
44 invert_match: true
45 redirect_path_matcher:
46 path:
當使用者按一下 login
時,應用程式會藉由呼叫 Envoy 中的 /login
路徑來啟動 OAuth 流程。
這會將使用者重新導向至 OAuth 提供者以進行授權/驗證,其中包含進一步的重新導向連結
34 default_expires_in: 600s
35 authorization_endpoint: https://127.0.0.1:7000/authorize
36 redirect_uri: "%REQ(x-forwarded-proto)%://%REQ(:authority)%/authorize"
37 forward_bearer_token: true
38 pass_through_matcher:
39 name: ":path"
成功授權/驗證後,使用者會透過此連結重新導向回應用程式,並附帶必要的 OAuth 授權碼 以繼續
44 invert_match: true
45 redirect_path_matcher:
46 path:
47 prefix: /authorize
48 signout_path:
49 path:
50 exact: /logout
然後,Envoy 會使用此授權碼及其用戶端金鑰來確認授權,並取得使用者的存取權杖
50 exact: /logout
51 credentials:
52 client_id: "0123456789"
53 token_secret:
54 name: token
55 sds_config:
56 path_config_source:
57 path: /etc/envoy/secrets/myhub-token-secret.yml
58 hmac_secret:
59 name: hmac
60 sds_config:
61 path_config_source:
1resources:
2- "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret
3 name: token
4 generic_secret:
5 secret:
6 inline_string: VERY_SECRET_KEY
登入後,您應該能夠使用 OAuth 憑證來查詢 API

警告
Envoy 的 OAuth 實作預設會針對端點上的所有路徑觸發 OAuth 流程。
這可能會在請求資產時輕易觸發 OAuth 洪水,並在 OAuth 流程失敗時導致迴圈。
可以藉由限制 OAuth 流程使用的路徑來避免這種情況。
沙箱範例會藉由反轉 pass_through_matcher,使其僅比對必要 OAuth 路徑來達成此目的。
提示
Myhub OAuth 提供者不會提供發出憑證的到期日。同樣地,Github 也可能會提供,也可能不會,視設定而定。就 OAuth2 規格而言,這是有效的。
如果授權提供者未包含到期日,Envoy 預設會使驗證失敗。
可以藉由設定 default_expires_in 來解決此問題
步驟 5:發出 API 查詢
對於沙箱應用程式,已設定 forward_bearer_token,因此 Envoy 也會將取得的存取權杖做為 Cookie 傳回給使用者

然後,此 Cookie 會在後續對代理 Myhub API 的任何請求中透過 Envoy 傳遞
步驟 6:即時重新載入程式碼變更
在瀏覽器開啟 https://127.0.0.1:10001 的情況下,對 UI 進行一些變更。
例如,您可以變更頁面標題
$ sed -i s/Envoy\ single\ page\ app\ example/DEV\ APP/g .local/ui/index.html
頁面應該會自動重新整理。
同樣地,對 .local/ui/src/...
中的 Typescript 應用程式元件所做的任何變更,都應該在瀏覽器中自動重新載入。
Envoy 中啟用此功能的方式是允許代理連線到 Vite 開發後端「升級」以使用 Websockets
22 "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
23 upgrade_configs:
24 - upgrade_type: websocket
25 http_filters:
26 - name: envoy.filters.http.oauth2
27 typed_config:
您可以使用以下指令檢視開發伺服器的日誌:
$ docker compose logs ui
single-page-app-ui-1 | Starting (dev.sh) with user: 1000 worker /home/worker
single-page-app-ui-1 | yarn run v1.22.19
single-page-app-ui-1 | $ vite --host 0.0.0.0 --port 3000
single-page-app-ui-1 |
single-page-app-ui-1 | VITE v5.0.10 ready in 119 ms
single-page-app-ui-1 |
single-page-app-ui-1 | ➜ Local: https://127.0.0.1:3000/
single-page-app-ui-1 | ➜ Network: http://172.30.0.5:3000/
如果您想與程序互動,也可以使用 docker attach
。
步驟 7:登出應用程式
登出時,應用程式會向 Envoy 設定的 signout_path 發出請求。
47 prefix: /authorize
48 signout_path:
49 path:
50 exact: /logout
51 credentials:
52 client_id: "0123456789"
53 token_secret:
這會清除 Envoy 儲存的 Cookie 和憑證,然後將使用者返回應用程式首頁。
應用程式也會清除任何與使用者會話相關的已儲存資料。
步驟 8:建置生產環境資源
首先,建立並設定自訂的 xds/
目錄。
您需要重新建置 Envoy,以確保它能看到正確的目錄。
$ mkdir .local/production
$ cp -a xds .local/production/
$ export XDS_PATH=./.local/production/xds
$ docker compose up --build -d envoy
您可以使用以下指令建置應用程式的生產環境資源:
$ docker compose run --rm ui build.sh
在建置 React 應用程式後,沙箱腳本會自動使用提供應用程式所需的靜態路由來更新 Envoy 的設定。
您可以檢視產生的路由
$ jq '.resources[0].filter_chains[0].filters[0].typed_config.route_config.virtual_hosts[0].routes' < .local/production/xds/lds.yml
[
{
"match": {
"path": "/assets/index-dKz4clFg.js"
},
"direct_response": {
"status": 200,
"body": {
"filename": "/var/www/html/assets/index-dKz4clFg.js"
}
},
"response_headers_to_add": [
{
"header": {
"key": "Content-Type",
"value": "text/javascript"
}
}
]
},
{
"match": {
"path": "/myhub.svg"
},
"direct_response": {
"status": 200,
"body": {
"filename": "/var/www/html/myhub.svg"
}
},
"response_headers_to_add": [
{
"header": {
"key": "Content-Type",
"value": "image/svg+xml"
}
}
]
},
{
"match": {
"prefix": "/"
},
"direct_response": {
"status": 200,
"body": {
"filename": "/var/www/html/index.html"
}
},
"response_headers_to_add": [
{
"header": {
"key": "Content-Type",
"value": "text/html"
}
}
]
}
]
注意
此設定會設定 Envoy 將必要檔案儲存在記憶體中。
這可能很適合單頁應用程式的使用案例,但對於許多或大型檔案來說,則無法很好地擴展。
提示
當您變更 javascript/typescript 檔案時,重新建置應用程式會建立指向已編譯資源的新路由。
在此情況下,Envoy 將透過 xDS 更新並使用新路由的資源。
如果您只變更未獲得新路由的資源 (例如 index.html
),您應該在重新建置應用程式後重新啟動 Envoy。
$ docker compose run --rm ui build.sh
$ docker compose restart envoy
步驟 9:瀏覽至生產環境伺服器
您可以透過 https://127.0.0.1:10000 瀏覽至此伺服器。
與開發端點不同,生產端點已設定:
TLS (自我簽署)
Gzip 壓縮
靜態提供的資源
步驟 10:設定 Github OAuth/API 存取權
提示
此沙箱說明了 Github 的設定,但您應該很容易就能將這些指示調整為其他提供者。
您需要設定 Github OAuth 或完整應用程式。後者提供更多控制權,通常是較佳的選擇。
這可以在 使用者 或組織層級完成。

注意
在設定 Github OAuth 時,您需要提供重新導向 URI。
這必須與 Envoy 中設定的 URI 相符。
為此範例的目的,將其設定為 https://127.0.0.1:10000。
您需要一個單獨的 OAuth 應用程式以進行開發。
根據您的使用案例,您可能還需要設定應用程式所需的任何權限。
設定完成後,您將需要提供的用戶端 ID 和密碼。
步驟 11:更新 Envoy 的設定以使用 Github
$ TOKEN_SECRET="GITHUB PROVIDED CLIENT SECRET"
$ export TOKEN_SECRET
$ envsubst < secrets/token-secret.tmpl.yml > .local/secrets/github-token-secret.yml
建立的檔案將在容器中的 /etc/envoy/secrets
下提供。
提示
以下指示使用 sed
,但您可能希望使用您的編輯器進行必要的取代。
對於每個設定,有 2 個地方需要更新,一個用於開發接聽器,另一個用於生產環境。
建立 Envoy 設定的副本,並告知 Docker 使用它
$ cp -a envoy.yml .local/envoy.yml
$ export ENVOY_CONFIG=.local/envoy.yml
對於 .local/envoy.yml
中的 OAuth 設定,設定 Github 提供的用戶端密碼
$ sed -i s@client_id:\ \"0123456789\"@client_id:\ \"$GITHUB_PROVIDED_CLIENT_ID\"@g .local/envoy.yml
使用 https://github.com/login/oauth/authorize
取代 authorization_endpoint
$ sed -i s@authorization_endpoint:\ https://127.0.0.1:7000/authorize@authorization_endpoint:\ https://github.com/login/oauth/authorize@g .local/envoy.yml
使用 https://github.com/login/oauth/access_token
取代 token_endpoint > uri
$ sed -i s@uri:\ http://myhub:7000/authenticate@uri:\ https://github.com/login/oauth/access_token@g .local/envoy.yml
將 token_secret > path 指向上面建立的 github-token-secret.yml
$ sed -i s@path:\ /etc/envoy/secrets/myhub-token-secret.yml@path:\ /etc/envoy/secrets/github-token-secret.yml@g .local/envoy.yml
取代 主機重寫
$ sed -i s@host_rewrite_literal:\ api.myhub@host_rewrite_literal:\ api.github.com@g .local/envoy.yml
最後新增 (或使用 github
和 github-api
叢集取代 myhub*
叢集) Github 設定的 叢集
$ cat _github-clusters.yml >> .local/envoy.yml
步驟 12:更新應用程式設定以使用 Github
我們需要告知應用程式提供者的名稱。
目前已實作 Myhub 和 Github 的提供者
7export const AuthProviders: IAuthProviders = {
8 "myhub": {
9 "name": "Myhub",
10 "icon": MyhubIcon},
11 "github": {
12 "name": "Github",
13 "icon": GithubIcon}}
如果您依照上述步驟操作,Vite 應用程式環境設定會從 .local/ui/.env*
讀取。
$ echo "VITE_APP_AUTH_PROVIDER=github" > .local/ui/.env.local
步驟 13:重新建置應用程式並重新啟動 Envoy
$ docker compose run --rm ui build.sh
$ docker compose up --build -d envoy
提示
請注意使用 up --build -d
,而不是 restart
。
這是必要的,因為我們已變更 envoy.yml
,該檔案會在建置時載入容器中。
瀏覽至生產環境伺服器 https://127.0.0.1:10000
您現在可以登入並使用 Github API。

另請參閱
- Envoy OAuth 篩選器
Envoy OAuth 篩選器的設定參考。
- Envoy OAuth 篩選器 API
Envoy OAuth 篩選器的 API 參考。
- OAuth2 規範
OAuth 2.0 是業界標準的授權協定。
- React
用於網頁和原生使用者介面的程式庫。
- Vite
下一代前端工具。
- Envoy Gzip 壓縮 API
Envoy gzip 壓縮的 API 和設定參考。
- 保護 Envoy 快速入門指南
保護 Envoy 的關鍵概念概述。
- Github OAuth 應用程式
有關設定 Github OAuth 應用程式的資訊。
- Github API
Github API 的參考。