设置 Microsoft Entra ID (Azure AD) 单点登录
OpenID Connect (OIDC) 是位于 OAuth 2.0 协议 之上的简单身份层。它允许客户端根据身份提供商执行的身份验证来验证最终用户的身份,并以可互操作和类似 REST 的方式获取有关最终用户的基本个人资料信息。通过 APISIX 和 Microsoft Entra ID(前身为 Azure AD),你可以实施基于 OIDC 的身份验证流程来保护你的 API 并启用单点登录 (SSO)。
Microsoft Entra ID 是微软基于云的身份和访问管理服务。它允许组织安全地管理和验证用户和设备,确保合适的人员拥有对公司资源的适当访问权限。Microsoft Entra ID 提供单点登录 (SSO)、多因素身份验证 (MFA) 以及与各种第三方应用程序的集成等功能。
本指南将向你展示如何使用 用户凭证进行身份验证 和 客户端凭证进行身份验证 将 APISIX 与 Microsoft Entra ID 集成。
前置条件
- 安装 Docker。
- 安装 cURL 以向服务发送请求进行验证。
- 按照 快速入门教程 在 Docker 或 Kubernetes 中启动一个新的 APISIX 实例。
- 创建一个具有有效订阅的 Azure 帐户。
在 Azure 中注册应用程序
登录到 Azure 门户,转到 App registrations 服务并注册一个新应用程序。

注册应用后,单击 Authentication 选项卡,然后单击 Add a platform。选择 Web 应用程序类型,并将新的重定向 URI http://localhost:9080/anything/callback 添加到 Web 页面下的 Redirect URIs 列表中。这是应用程序在使用 Microsoft Entra ID 成功进行身份验证后将用户重定向到的地址。单击 Configure 保存更改。

要将 Microsoft Entra ID 配置为使用 v2.0 令牌,请编辑你的应用程序 Manifest,并将 accessTokenAcceptedVersion 设置为 2。

在 Certificates & Secrets 选项卡中,创建一个客户端 secret 并将该值保存到安全位置,以便稍后用于 APISIX OIDC 插件配置。你只能查看该 secret 一次。

导航回 Overview 选项卡,找到 Directory (tenant) ID 和 Application (client) ID。将它们连同客户端 secret 一起保存到环境变量:
# 替换为你的配置值
export TENANT_ID=dcbd8da3-e0b3-486c-9212-08a199dc3451
export CLIENT_ID=e0951842-d546-4c63-9e9e-d33a527673de
export CLIENT_SECRET=wSY8Q~x4z2Tn6Rq5lA4NTtZ6GLBMGvZF_R2LEcPx
配置 APISIX
在本节中,你将创建一个带有 OIDC 的路由,该路由将客户端请求转发到 httpbin.org,这是一个公共 HTTP 请求和响应服务。
httpbin.org 的路由 /anything/{anything} 以 JSON 类型返回请求数据中传递的任何内容,例如方法、参数和标头。
启用 OIDC 插件
创建路由并启用 openid-connect 插件:
- Admin API
- ADC
- Ingress Controller
curl -i "http://127.0.0.1:9180/apisix/admin/routes" -X PUT -d '
{
"id": "auth-with-oidc",
"uri":"/anything/*",
"plugins": {
"openid-connect": {
// Annotate 1
"client_id": "'"$CLIENT_ID"'",
// Annotate 2
"client_secret": "'"$CLIENT_SECRET"'",
// Annotate 3
"discovery": "https://login.microsoftonline.com/'"$TENANT_ID"'/v2.0/.well-known/openid-configuration",
"scope": "openid",
// Annotate 4
"redirect_uri": "http://localhost:9080/anything/callback",
// Annotate 5
"bearer_only": false,
"session": {
// Annotate 6
"secret": "f86cf31663a9c9fa0a28c2cc78badef1"
}
}
},
"upstream":{
"type":"roundrobin",
"nodes":{
"httpbin.org:80":1
}
}
}'
❶ client_id:Microsoft Entra ID 客户端 ID。
❷ client_secret:Microsoft Entra ID 客户端 secret。
❸ discovery:Microsoft Entra ID 的 OIDC 发现文档 URI。
❹ redirect_uri:使用 Microsoft Entra ID 身份验证后重定向到的 URI。
❺ bearer_only:对于授权码流,设置为 false。
❻ session.secret:替换为你用于会话加密和 HMAC 操作的密钥。当 bearer_only 为 false 时为必需。
services:
- name: httpbin Service
routes:
- uris:
- /anything/*
name: auth-with-oidc
plugins:
openid-connect:
// Annotate 1
client_id: 'e0951842-d546-4c63-9e9e-d33a527673de'
// Annotate 2
client_secret: 'wSY8Q~x4z2Tn6Rq5lA4NTtZ6GLBMGvZF_R2LEcPx'
// Annotate 3
discovery: 'https://login.microsoftonline.com/dcbd8da3-e0b3-486c-9212-08a199dc3451/v2.0/.well-known/openid-configuration'
scope: 'openid'
// Annotate 4
redirect_uri: 'http://localhost:9080/anything/callback'
// Annotate 5
bearer_only: false
session:
// Annotate 6
secret: f86cf31663a9c9fa0a28c2cc78badef1
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
❶ client_id:Microsoft Entra ID 客户端 ID。
❷ client_secret:Microsoft Entra ID 客户端 secret。
❸ discovery:Microsoft Entra ID 的 OIDC 发现文档 URI。
❹ redirect_uri:使用 Microsoft Entra ID 身份验证后重定向到的 URI。
❺ bearer_only:对于授权码流,设置为 false。
❻ session.secret:替换为你用于会话加密和 HMAC 操作的密钥。当 bearer_only 为 false 时为必需。
将配置同步到 APISIX:
adc sync -f adc.yaml
- Gateway API
- APISIX CRD
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: ingress-apisix
name: auth-plugin-config
spec:
plugins:
- name: openid-connect
config:
// Annotate 1
client_id: e0951842-d546-4c63-9e9e-d33a527673de
// Annotate 2
client_secret: wSY8Q~x4z2Tn6Rq5lA4NTtZ6GLBMGvZF_R2LEcPx
// Annotate 3
discovery: https://login.microsoftonline.com/dcbd8da3-e0b3-486c-9212-08a199dc3451/v2.0/.well-known/openid-configuration
scope: openid
// Annotate 4
redirect_uri: http://localhost:9080/anything/callback
// Annotate 5
bearer_only: false
session:
// Annotate 6
secret: f86cf31663a9c9fa0a28c2cc78badef1
---
apiVersion: v1
kind: Service
metadata:
namespace: ingress-apisix
name: httpbin-external-domain
spec:
type: ExternalName
externalName: httpbin.org
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: ingress-apisix
name: auth-with-oidc
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: PathPrefix
value: /anything/*
filters:
- type: ExtensionRef
extensionRef:
group: apisix.apache.org
kind: PluginConfig
name: auth-plugin-config
backendRefs:
- name: httpbin-external-domain
port: 80
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: ingress-apisix
name: httpbin-external-domain
spec:
externalNodes:
- type: Domain
name: httpbin.org
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: ingress-apisix
name: auth-with-oidc
spec:
ingressClassName: apisix
http:
- name: auth-with-oidc
match:
paths:
- /anything/*
plugins:
- name: openid-connect
enable: true
config:
// Annotate 1
client_id: e0951842-d546-4c63-9e9e-d33a527673de
// Annotate 2
client_secret: wSY8Q~x4z2Tn6Rq5lA4NTtZ6GLBMGvZF_R2LEcPx
// Annotate 3
discovery: https://login.microsoftonline.com/dcbd8da3-e0b3-486c-9212-08a199dc3451/v2.0/.well-known/openid-configuration
scope: openid
// Annotate 4
redirect_uri: http://localhost:9080/anything/callback
// Annotate 5
bearer_only: false
session:
// Annotate 6
secret: f86cf31663a9c9fa0a28c2cc78badef1
upstreams:
- name: httpbin-external-domain
❶ client_id:Microsoft Entra ID 客户端 ID。
❷ client_secret:Microsoft Entra ID 客户端 secret。
❸ discovery:Microsoft Entra ID 的 OIDC 发现文档 URI。
❹ redirect_uri:使用 Microsoft Entra ID 身份验证后重定向到的 URI。
❺ bearer_only:对于授权码流,设置为 false。
❻ session.secret:替换为你用于会话加密和 HMAC 操作的密钥。当 bearer_only 为 false 时为必需。
将配置应用到你的集群:
kubectl apply -f oidc-route.yaml
使用用户凭证进行身份验证
在浏览器中导航到 http://localhost:9080/anything/test。你应该被重定向到 Microsoft Entra ID 登录页面:

你可以为 Microsoft Entra ID 登录页面定制自己的品牌。查看如何 配置你的公司品牌 在登录页面上。
使用你的 Azure 凭证登录。如果成功,你应该在浏览器中看到类似以下的响应:
{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "en-us",
"Cookie": "session=...",
"Host": "localhost",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.6.1 Safari/605.1.15",
"X-Access-Token": "eyJ...",
"X-Amzn-Trace-Id": "Root=1-65698cfb-262bc17d50bca6de3e855301",
"X-Forwarded-Host": "localhost",
"X-Id-Token": "eyJ...",
"X-Userinfo": "eyJ..."
},
"json": null,
"method": "GET",
"origin": "172.24.0.1, 108.**.**.**",
"url": "http://localhost/anything/test"
}
使用客户端凭证进行身份验证
客户端凭证流涉及机器对机器 (M2M) 应用程序在没有用户参与的情况下与服务交换凭证。
在本节中,你将使用额外的 OIDC 配置更新现有路由,并使用访问令牌向 Microsoft Entra ID 进行身份验证。
更新 OIDC 插件
更新路由上的 OIDC 插件以使用身份服务器的 JWKS 端点来验证令牌:
- Admin API
- ADC
- Ingress Controller
curl -i "http://127.0.0.1:9180/apisix/admin/routes/auth-with-oidc" -X PATCH -d '
{
"plugins": {
"openid-connect": {
"use_jwks": true
}
}
}'
services:
- name: httpbin Service
routes:
- uris:
- /anything/*
name: auth-with-oidc
plugins:
openid-connect:
use_jwks: true
client_id: 'e0951842-d546-4c63-9e9e-d33a527673de'
client_secret: 'wSY8Q~x4z2Tn6Rq5lA4NTtZ6GLBMGvZF_R2LEcPx'
discovery: 'https://login.microsoftonline.com/dcbd8da3-e0b3-486c-9212-08a199dc3451/v2.0/.well-known/openid-configuration'
scope: 'openid'
redirect_uri: 'http://localhost:9080/anything/callback'
bearer_only: false
session:
secret: f86cf31663a9c9fa0a28c2cc78badef1
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
将配置同步到 APISIX:
adc sync -f adc.yaml
- Gateway API
- APISIX CRD
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: ingress-apisix
name: auth-plugin-config
spec:
plugins:
- name: openid-connect
config:
use_jwks: true
client_id: e0951842-d546-4c63-9e9e-d33a527673de
client_secret: wSY8Q~x4z2Tn6Rq5lA4NTtZ6GLBMGvZF_R2LEcPx
discovery: https://login.microsoftonline.com/dcbd8da3-e0b3-486c-9212-08a199dc3451/v2.0/.well-known/openid-configuration
scope: openid
redirect_uri: http://localhost:9080/anything/callback
bearer_only: false
session:
secret: f86cf31663a9c9fa0a28c2cc78badef1
---
apiVersion: v1
kind: Service
metadata:
namespace: ingress-apisix
name: httpbin-external-domain
spec:
type: ExternalName
externalName: httpbin.org
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: ingress-apisix
name: auth-with-oidc
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: PathPrefix
value: /anything/*
filters:
- type: ExtensionRef
extensionRef:
group: apisix.apache.org
kind: PluginConfig
name: auth-plugin-config
backendRefs:
- name: httpbin-external-domain
port: 80
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: ingress-apisix
name: httpbin-external-domain
spec:
externalNodes:
- type: Domain
name: httpbin.org
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: ingress-apisix
name: auth-with-oidc
spec:
ingressClassName: apisix
http:
- name: auth-with-oidc
match:
paths:
- /anything/*
plugins:
- name: openid-connect
enable: true
config:
use_jwks: true
client_id: e0951842-d546-4c63-9e9e-d33a527673de
client_secret: wSY8Q~x4z2Tn6Rq5lA4NTtZ6GLBMGvZF_R2LEcPx
discovery: https://login.microsoftonline.com/dcbd8da3-e0b3-486c-9212-08a199dc3451/v2.0/.well-known/openid-configuration
scope: openid
redirect_uri: http://localhost:9080/anything/callback
bearer_only: false
session:
secret: f86cf31663a9c9fa0a28c2cc78badef1
upstreams:
- name: httpbin-external-domain
将配置应用到你的集群:
kubectl apply -f oidc-route.yaml
测试访问令牌
获取 Azure 中注册的测试应用程序的访问令牌:
curl -i "https://login.microsoftonline.com/$TENANT_ID/oauth2/v2.0/token" -X POST \
-d 'client_id='$CLIENT_ID'' \
-d 'client_secret='$CLIENT_SECRET'' \
-d 'scope='$CLIENT_ID'/.default' \
-d 'grant_type=client_credentials'
预期的响应类似于以下内容:
{
"token_type": "Bearer",
"expires_in": 3599,
"ext_expires_in": 3599,
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ii1LSTNROW5OUjdiUm9meG1lWm9YcWJIWkdldyJ9.eyJhdWQiOiJlMDk1MTg0Mi1kNTQ2LTRjNjMtOWU5ZS1kMzNhNTI3NjczZGUiLCJpc3MiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vZGNiZDhkYTMtZTBiMy00ODZjLTkyMTItMDhhMTk5ZGMzNDUxL3YyLjAiLCJpYXQiOjE2OTQ2MDczMzAsIm5iZiI6MTY5NDYwNzMzMCwiZXhwIjoxNjk0NjExMjMwLCJhaW8iOiJBU1FBMi84VUFBQUFHZXcvTjhPQm1OSEtaK1cydVNnR0NNckhwRlNERmVuNUNBcTVONG1QQ2ZzPSIsImF6cCI6ImUwOTUxODQyLWQ1NDYtNGM2My05ZTllLWQzM2E1Mjc2NzNkZSIsImF6cGFjciI6IjEiLCJvaWQiOiIxODA5NTNiZi1lZDZlLTRjNjUtYmRiZS01Y2JlNmRhMTI4OTYiLCJyaCI6IjAuQVRvQW80MjkzTFBnYkVpU0VnaWhtZHcwVVVJWWxlQkcxV05NbnA3VE9sSjJjOTdoQUFBLiIsInN1YiI6IjE4MDk1M2JmLWVkNmUtNGM2NS1iZGJlLTVjYmU2ZGExMjg5NiIsInRpZCI6ImRjYmQ4ZGEzLWUwYjMtNDg2Yy05MjEyLTA4YTE5OWRjMzQ1MSIsInV0aSI6IlM5anBfWS1qUjBhcm9lS3NVdnNqQUEiLCJ2ZXIiOiIyLjAifQ.bAt8rh56MK7igDZws0mtSqXDhHvwIyKoxOW7uqSD5aWBaXPxINpNTqIW04n4_p14uLhBlxSufV8WHmS5V1Pdv-QENu9VMUs00blOH38TX0S3WfyCkYuecvWnHc4kYi4TFxTVk1nTvhU7LgOYIHLDb04rRxP-D0tFJ7qo2gI2nSvDChEPCID8WkugPbXJyo1gc49UAuv75d2PhFkidIigDq_DGQQoa88ZLW1iDcQYVgTitEg9zhqSlYksOq1xGClB16sSubnKF6dwqXOfUamAMeu41YLDdgOAb3bS3J54OOe5uUliemHxWo4Z-rfBOI8uOKUioVLv2RImaHylhutaeA"
}
将访问令牌保存到环境变量:
# 替换为你的访问令牌
export ACCESS_TOKEN="eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ikc2elVuYzgtM0JrVlgtZmdnMTdKNSJ9.eyJpc3MiOiJodHRwczovL2Rldi00bGc0aWZzcTRqdnBuN3MyLnVzLmF1dGgwLmNvbS8iLCJzdWIiOiJlQUM4VVRWUEZpcnVmT2g0YTFEWnRjN0YyMHo3eUd1dkBjbGllbnRzIiwiYXVkIjoiaHR0cHM6Ly9jbGllbnRjcmVkZW50aWFscy5jb20iLCJpYXQiOjE2OTMwNDAwMjcsImV4cCI6MTY5MzEyNjQyNywiYXpwIjoiZUFDOFVUVlBGaXJ1Zk9oNGExRFp0YzdGMjB6N3lHdXYiLCJndHkiOiJjbGllbnQtY3JlZGVudGlhbHMifQ.aePOiFlW0q0mlrQwKdtP1MGfY2nX7TSnTrEjoJI03aG7lBCHhPX_WwszhYvtM5c_cyQtcI6R4ibPskpTssdEXGCe2wbOhstPWeIb9rCFf_kA_g0p1wDM8j8egRfl7PLmFffaEmU0eNrgmjTgYQ0Erk63XDykPFOFWiQKPfDQ2hf4jz_3J_VKNqwy7yQuxisnD5TysybGmrONoiBjYLGIymk1ii-qKEoNt5_DRv10aSBwyRtxDZbiwhAKcWNO7zLaJVmZZLg1aTiRYxgIOU-_AP4iAR6Y4vK_GxyHqf7G6j6yH8wqCj8Nm2bLEg8Gqb9Fd-xbpbQCiC3X14ja5NTYtw"
使用有效的访问令牌授权标头向路由发送请求:
curl -i "http://127.0.0.1:9080/anything/test" -H "Authorization: Bearer $ACCESS_TOKEN"
HTTP/1.1 200 OK 响应验证了客户端应用程序能够对 API 进行授权调用。