本文介绍如何使用 Docker Compose 在本地环境中运行 Microsoft Entra ID 身份验证 SDK(sidecar)。 启动四容器堆栈 - 聊天代理、sidecar、下游天气 API 和本地大型语言模型(如 (Ollama)。 然后,通过聊天 UI 发送查询,并观察从代理到 API 的完整令牌流。 在开始之前,请查看所需工具、Microsoft Entra租户对象和本地环境设置的先决条件。
此示例演示了两种执行模式和两个标识流:
| 自治 (仅限应用) | OBO (代表用户) | |
|---|---|---|
| 直接 (无 LLM) | 代理提取令牌并直接调用天气 API。 | 同样,但 sidecar 会交换已登录用户的令牌。 |
| Ollama + LangChain | LangGraph ReAct 代理决定何时调用该工具 get_weather 。 |
代理也是如此,但它通过用户令牌进行传递。 |
先决条件
此示例适用于 macOS、Linux 和 Windows 10/11。
| Requirement | macOS | Linux | Windows操作系统 |
|---|---|---|---|
| Docker | Docker Desktop | Docker 引擎 + Compose v2 | Docker Desktop (建议使用 WSL 2 后端) |
| PowerShell 7+ | brew install --cask powershell |
在 Linux 上安装 PowerShell | 内置(或安装 PowerShell 7+) |
| Azure CLI | brew install azure-cli |
安装 Azure CLI | winget install -e Microsoft.AzureCLI |
您还需要一个 Microsoft Entra 租户,其中包含以下对象:
- 具有客户端密钥的代理程序标识蓝图。 记录其值
BLUEPRINT_APP_ID和BLUEPRINT_CLIENT_SECRET。 - 从该蓝图生成的代理身份。 记录
AGENT_CLIENT_ID。 - (仅限 OBO 流)SPA 应用注册。 记录
CLIENT_SPA_APP_ID。
若要创建这些对象,请遵循 Microsoft Entra 智能体 ID 示例存储库中的 PowerShell 工作流。 工作流创建蓝图应用、代理标识,以及用于 OBO 登录的 SPA 应用( 可选)。
Ollama 不是 主机上的先决条件 - 它在 Compose 堆栈中运行并自动拉取 qwen2.5:1.5b 。
克隆示例存储库
运行以下命令,下载示例项目并更改为 sidecar 目录,其中包含本演练的 Docker Compose 配置和代理源代码:
git clone https://github.com/microsoft/entra-agentid-samples.git
cd entra-agentid-samples/sidecar/dev
Sidecar 本地开发架构
该堆栈在内部 Docker 网络上运行四个容器:llm-agent-dev(Flask 聊天 UI,通过 3003 端口对外提供服务)、agent-id-sidecar-dev(Microsoft Entra ID 身份验证 SDK 边车容器)、weather-api-dev(用于验证代理令牌的下游 API)和 ollama-dev(本地 LLM)。 仅聊天 UI 向宿主机公开;sidecar 和天气 API 仅可从 Docker 网络内部访问。
所有四个容器都在共享 Docker 网(agent-network-dev)上运行。 仅聊天界面(端口 3003)向你的主机公开。 边车和天气 API 没有主机端口,使令牌端点保持在信任边界内。
请求路径的工作方式如下所示:
- 在浏览器中打开
http://localhost:3003并发送查询。 - 代理 (
llm-agent-dev) 接收查询,并决定调用get_weather该工具。 - 该工具在
GET /AuthorizationHeader...?AgentIdentity={agentId}请求 sidecar 提供授权标头。 - sidecar (
agent-id-sidecar-dev) 使用 Microsoft Entra ID 执行 OAuth 2.0 交换,并接收令牌(TR)。 - Sidecar 将
Authorization: Bearer TR标头返回到代理。 - 代理使用该标头调用天气 API (
weather-api-dev)。 - 天气 API 验证 TR(JSON Web 密钥集(JWKS)、RS256 签名算法、颁发者、到期、受众)并返回天气数据。
代理从不直接与Microsoft Entra ID联系,也永远不会看到凭据。 它向边车请求 Authorization 标头,接收 Bearer 令牌,并将该令牌传递给天气 API。 只有边车与 login.partner.microsoftonline.cn 通信。
了解令牌流动
自治流使用两个令牌: T1 (来自客户端凭据的蓝图应用令牌)和 TR (下游 API 的代理令牌)。 OBO 流添加了第三个: Tc (来自 MSAL.js 浏览器登录的用户访问令牌)。 Sidecar 处理所有令牌获取和缓存,以便代理代码永远不会直接管理凭据。
了解自主令牌流
无需用户登录。 代理通过蓝图的客户端凭据对自身进行身份验证。
- 用户通过聊天 UI 发送查询。
- 代理(或 LangGraph ReAct 代理)决定调用
get_weather该工具。 - 该工具从 sidecar 请求位于
GET /AuthorizationHeaderUnauthenticated/graph-app?AgentIdentity={agentAppId}的授权标头。 - 边车与 Microsoft Entra ID 执行客户端凭据交换并接收 TR(仅应用,
idtyp=app)。 - 该工具通过
Authorization: Bearer TR调用天气 API。 - 天气 API 验证 TR(签名、颁发者、到期、受众)并返回天气数据。
了解 OBO(代表)令牌流
代理代表已登录用户执行操作。 边车执行三步令牌交换。
- 用户在浏览器中通过 MSAL.js 登录并接收 Tc(用户访问令牌,受众 =
api://{BlueprintAppId})。 - 用户发送查询。 代理与请求一起接收 Tc。
- 工具在
GET /AuthorizationHeader/graph处向边车请求授权标头,传递Authorization: Bearer Tc和?AgentIdentity={agentAppId}。 - sidecar 验证 Tc,执行客户端凭据交换以获取 T1,然后执行 OBO 交换来获取 TR(委托,
idtyp=user)。 OBO 交换使用assertion=Tc、client_assertion=T1和grant_type=jwt-bearer。 - 该工具通过
Authorization: Bearer TR调用天气 API。 - 天气 API 验证 TR 并返回天气数据。 TR 代表已登录用户执行操作。
配置环境变量
Tip
如果以前运行中有一个.env文件,TENANT_IDBLUEPRINT_APP_ID并且BLUEPRINT_CLIENT_SECRETAGENT_CLIENT_ID已填充,请跳到“启动堆栈”。 Microsoft Entra 对象在容器重启和 docker compose down 后保留。
复制该示例环境文件并添加您的 Microsoft Entra 参数值:
从示例模板创建本地环境文件,以便填写租户和应用注册值:
cp .env.example .env
在编辑器中打开 .env 并设置以下值:
| Variable | 说明 |
|---|---|
TENANT_ID |
Microsoft Entra租户标识。 |
BLUEPRINT_APP_ID |
蓝图应用注册客户端 ID。 sidecar 作为此应用进行身份验证。 |
BLUEPRINT_CLIENT_SECRET |
蓝图客户端密码。 仅用于本地开发。 |
AGENT_CLIENT_ID |
你的智能体标识客户端 ID。 作为 AgentIdentity 查询参数传递给边车。 |
CLIENT_SPA_APP_ID |
SPA 应用注册客户端 ID。 仅适用于 OBO 流程。 |
OLLAMA_MODEL |
要使用的 Ollama 模型。 默认值为 qwen2.5:1.5b. |
自治流需要TENANT_ID、BLUEPRINT_APP_ID、BLUEPRINT_CLIENT_SECRET和AGENT_CLIENT_ID。 OBO 流也需要 CLIENT_SPA_APP_ID。
此 Sidecar 示例使用 ClientSecret 作为凭据来源类型。 通过在 AzureAd__ClientCredentials__0__SourceType 中的 docker-compose.yml 设置,Sidecar 支持以下凭据类型:
-
ClientSecret: 仅限本地开发。 此类型是此示例的默认值。 -
SignedAssertionFromManagedIdentity:部署在Azure上。 建议采用零秘密原则进行生产。 -
KeyVault:来自Azure 密钥保管库的证书。 -
StoreWithThumbprint: 来自本地计算机存储的证书。
设置 OBO 登录(可选)
若要测试代理流,请创建 SPA 应用并配置 OBO 同意。 从存储库根目录运行以下脚本对之一:
# Create the SPA app registration for MSAL.js browser sign-in
bash ../../scripts/setup-obo-client-app.sh
# → prints CLIENT_SPA_APP_ID
# Wire up the OBO scope + admin consent on the Blueprint
bash ../../scripts/setup-obo-blueprint.sh
运行脚本后,将 CLIENT_SPA_APP_ID 该值添加到 .env 文件。
启动堆栈
运行以下命令,生成容器映像,并在分离模式下启动所有四个服务:
docker compose up --build -d
第一次运行需要约 30 秒,Ollama 拉取 qwen2.5:1.5b 模型。 若要验证本地示例堆栈是否正在运行,并且 sidecar 和 Ollama 等组件已准备就绪,请查询状态终结点:
curl http://localhost:3003/api/status
响应显示 ollama_available: true 当堆栈就绪时。
通过聊天 UI 发送查询
执行以下步骤,通过聊天 UI 发送测试查询并观察令牌流:
在浏览器中打开
http://localhost:3003。在标头栏中,验证 租户 ID 和 代理 ID 是否显示。
使用两个开关选择演示配置:
- 执行模式:选择 “直接 ”以跳过 LLM 并直接调用天气 API,或选择 Ollama 以使用 LangChain ReAct 代理。
- 标识流:为应用专用令牌选择 自主,或选择 OBO (代表) 代表已登录用户执行操作。 对于 OBO,请选择 “登录 ”以通过 MSAL.js 弹出窗口进行身份验证。
发送预填充的查询“达拉斯天气?”并查看结果。
在右侧面板中,展开标识跟踪以查看令牌流的每个步骤:
- 向 sidecar 请求令牌,包括
AgentIdentity参数。 - 每个令牌的解码 JWT 声明 (适用于 OBO: Tc, T1, TR; 适用于自治: T1, TR)。
- 下游 API 验证结果,包括签名(JWKS、RS256)、颁发者、到期和受众检查。
- 向 sidecar 请求令牌,包括
排查常见问题
| 症状 | 可能的原因 | 修复 |
|---|---|---|
/api/status 返回 ollama_available: false |
模型仍在下载。 | 等待大约 30 秒。 使用 docker logs ollama-dev 检查日志。 |
天气 API 返回 401 Unauthorized |
令牌租户不匹配、过期的密钥或签名检查失败。 | 验证 TENANT_ID 是否与蓝图的租户匹配。 使用 docker logs agent-id-sidecar-dev 检查 sidecar 日志。 |
| LLM 在不调用该工具的情况下返回天气 | 模型 qwen2.5:1.5b 太小,无法进行可靠的工具调用。 |
将OLLAMA_MODEL文件中的qwen2.5:7b更改为llama3.1:8b或.env。 |
| OBO 登录弹出窗口被阻止 | 浏览器弹出窗口阻止程序处于活动状态。 | 允许弹出窗口。localhost:3003 |
4xx Sidecar 在 OBO 期间出错 |
CLIENT_SPA_APP_ID 缺少或 SPA 重定向 URI 不匹配。 |
重新运行 OBO 安装脚本。 确认 http://localhost:3003 列在 SPA 的重定向 URI 中。 |
若要诊断启动、身份验证或下游 API 问题,请运行以下命令显示每个容器的日志:
docker logs llm-agent-dev
docker logs agent-id-sidecar-dev
docker logs weather-api-dev
清理资源
使用完毕后,停止容器。 选择符合需求的清理级别。 第一个命令会停止演示容器,同时保留卷和映像,以便稍后更快地重启:
# Stop containers, keep volumes and images
docker compose down
# Stop containers and remove the Ollama model cache
docker compose down -v
# Remove containers, volumes, and images
docker compose down -v --rmi all
