内容
# 🤫 身份验证远程 MCP 服务器
本示例演示了如何在 Azure 上部署 Entra ID 保护的 MCP 服务器。
该示例还使用了一种授权模式,客户端首先为 MCP 服务器获取令牌,然后使用[代理流](https://learn.microsoft.com/entra/identity-platform/v2-oauth2-on-behalf-of-flow)将其交换为可与[Microsoft Graph](https://learn.microsoft.com/graph/overview)一起使用的令牌。整个过程完全无需密钥。
## ⚠️ 重要:实验性实现
>[!IMPORTANT]
> **这是实验性实现,不应用于生产场景。**
>
> 本示例演示了通过实现 OAuth 2.0 动态客户端注册和 PKCE 流模式来使用 Entra ID 构建受保护的 MCP 服务器,这些模式适用于 Entra ID 对这些标准的本地支持存在当前空白的情况。虽然它展示了技术可能性,但仅用于教育和概念验证目的。
>
> 对于生产场景,请考虑使用预注册应用程序和标准 OAuth 流的已建立身份验证模式。
## 使用的内容
- ⚡ [Azure Functions](https://learn.microsoft.com/azure/azure-functions/functions-overview)
- 🕸️ [Azure API 管理](https://learn.microsoft.com/azure/api-management/api-management-key-concepts)
- 💪 [Bicep](https://learn.microsoft.com/azure/azure-resource-manager/bicep/)
- 🐍 [Python](https://www.python.org/)
- 🚀 [Azure 开发人员 CLI](https://learn.microsoft.com/azure/developer/azure-developer-cli/install-azd?tabs=winget-windows%2Cbrew-mac%2Cscript-linux&pivots=os-windows)
>[!NOTE]
>您可以使用[模型上下文协议检查器](https://modelcontextprotocol.io/docs/tools/inspector)或[Visual Studio Code](https://code.visualstudio.com)测试此 MCP 服务器。
## 授权流程如何工作
此实现使用具有 PKCE(代码交换证明密钥)的复杂 OAuth 2.0 流安全地对 MCP 客户端进行身份验证。下面是其工作原理:
```mermaid
sequenceDiagram
participant Client as MCP Client
participant Browser as User's Browser
participant APIM as API Management
participant Entra as Entra ID
participant Function as Azure Function
participant Graph as Microsoft Graph
Note over Client,Graph: 1. Discovery & Registration
Client->>APIM: GET /.well-known/oauth-authorization-server
APIM->>Client: OAuth metadata (authorization_endpoint, token_endpoint, etc.)
Client->>APIM: POST /register (Dynamic Client Registration)
Note over APIM: Store client info in CosmosDB<br/>Generate unique client_id
APIM->>Client: Client credentials (client_id, no secret)
Note over Client,Graph: 2. Authorization with PKCE
Note over Client: Generate code_verifier & code_challenge
Client->>Browser: Open authorization URL with PKCE params
Browser->>APIM: GET /authorize?client_id=...&code_challenge=...
Note over APIM: Check for existing consent cookie<br/>🍪 __Host-MCP_APPROVED_CLIENTS
alt No previous consent
APIM->>Browser: Redirect to /consent page
Note over Browser: User reviews permissions and clicks "Allow"
Browser->>APIM: POST /consent (with CSRF protection)
Note over APIM: Set consent cookie<br/>🍪 __Host-MCP_APPROVED_CLIENTS<br/>🍪 __Host-MCP_CONSENT_STATE
end
APIM->>Browser: Redirect to Entra ID with state correlation
Note over APIM: Set Entra state cookie<br/>🍪 __Host-MCP_ENTRA_STATE<br/>(contains sessionId|entraidState|clientState)
Browser->>Entra: Authorize with Entra ID
Note over Browser: User authenticates with Entra ID
Entra->>APIM: Callback with authorization code
Note over APIM: Validate state correlation<br/>Exchange code for Entra access token<br/>Generate encrypted session token
APIM->>Browser: Redirect with MCP authorization code
Note over Client,Graph: 3. Token Exchange
Browser->>APIM: POST /token (code + code_verifier)
Note over APIM: Validate PKCE challenge<br/>Return encrypted session token
APIM->>Browser: Access token (encrypted session key)
Browser->>Client: Token for MCP communication
Note over Client,Graph: 4. Authenticated MCP Communication
Client->>APIM: GET /mcp/sse (with Bearer token)
Note over APIM: Decrypt session token<br/>Lookup cached Entra token<br/>Add to request for downstream
APIM->>Function: Forward with Entra access token
Function->>Graph: API calls using on-behalf-of flow
Graph->>Function: User data
Function->>APIM: MCP response
APIM->>Client: Authenticated MCP response
```
### 安全功能和使用的 Cookie
此实现使用多种安全机制和 Cookie 以确保流程安全:
| Cookie | 目的 |
|--------|---------|
| `__Host-MCP_APPROVED_CLIENTS` | 记录用户对特定客户端的同意 |
| `__Host-MCP_DENIED_CLIENTS` | 记录拒绝的同意以防止重复提示 |
| `__Host-MCP_CONSENT_STATE` | 验证同意表单提交 |
| `__Host-MCP_ENTRA_STATE` | 将 Entra ID 回调与原始请求关联 |
| `__Host-MCP_CSRF_TOKEN` | 保护同意表单免受 CSRF 攻击 |
>[!NOTE]
> 所有 Cookie 都使用 `__Host-` 前缀、Secure、HttpOnly 和 SameSite=Lax 以实现最大安全性(`__Host-MCP_ENTRA_STATE` 除外,它使用 SameSite=None 进行跨站点重定向)。
**关键安全功能:**
- 🔐 **PKCE(代码交换证明密钥)** - 防止授权代码拦截
- 🍪 **安全 Cookie** - 所有 Cookie 都使用 `__Host-` 前缀以实现最大安全性
- 🛡️ **CSRF 保护** - 双提交 Cookie 模式,具有恒定时间验证
- 🔄 **状态关联** - 多层状态验证防止会话固定
- 🔒 **加密会话令牌** - 会话标识符经过 AES 加密
- ⏰ **令牌缓存** - Entra 令牌缓存具有加密会话密钥以提高性能
## 入门指南
按照以下步骤开始:
1. [安装 Azure 开发人员 CLI](https://learn.microsoft.com/azure/developer/azure-developer-cli/install-azd)。
2. 在本地克隆存储库:
```bash
git clone https://github.com/localden/remote-auth-mcp-apim-py
```
3. 在终端中导航到存储库:
```bash
cd remote-auth-mcp-apim-py
```
4. 确保 `Microsoft.App` 资源提供程序已在您的订阅中注册,可以在 [Azure 门户](https://learn.microsoft.com/azure/azure-resource-manager/management/resource-providers-and-types#azure-portal) 或通过运行以下 [Azure CLI 命令](https://learn.microsoft.com/cli/azure/install-azure-cli?view=azure-cli-latest) 进行:
```bash
az login
az provider register --namespace Microsoft.App --wait
```
5. 登录到 Azure 开发人员 CLI:
```bash
azd auth login
```
6. 将项目部署到 Azure:
```bash
azd up
```
>[!IMPORTANT]
> 部署此项目将产生 Azure 成本。如果您部署用于测试和实验,请确保在测试后删除创建的资源组。
## 部署和测试项目
当您运行 `azd up` 时,[`infra`](https://github.com/localden/remote-auth-mcp-apim-py/tree/main/infra) 目录中声明的资源将在您的 Azure 帐户中配置。您可以浏览现有的 Bicep 文件以查看将自动部署哪些基础设施。

部署完成后,您将在终端中看到**端点**打印出来:

例如,在上面的屏幕截图中,端点是 `https://apim-2lzunaz2nu642.azure-api.net/mcp/sse`。复制它。
>[!NOTE]
> 在下一步之前,请确保您已安装 [Node.js](https://nodejs.org/en) - 它是运行[模型上下文协议检查器](https://modelcontextprotocol.io/docs/tools/inspector)所必需的。
在您的终端中运行:
```bash
npx @modelcontextprotocol/inspector@0.9.0
```
>[!NOTE]
> 我们使用`0.9.0`版本的模型上下文协议检查器,因为它是测试受保护的 MCP 服务器时最稳定的版本。
这将为您提供一个端点,您可以在此处看到模型上下文协议检查器在本地运行。 在浏览器中打开 URL。
切换 **传输类型** 为 **SSE** 并将 **URL** 设置为您运行部署后获得的端点。单击 **连接**。

您将被提示使用您部署基础设施的租户中的凭据进行身份验证。 Entra ID 应用程序在部署时动态注册 - 一个用于服务器,另一个用于[代理流](https://learn.microsoft.com/entra/identity-platform/v2-oauth2-on-behalf-of-flow)以获取[Microsoft Graph](https://learn.microsoft.com/graph/use-the-api)访问权限。
一旦您同意,您将被重定向回模型上下文协议检查器登录页面。 等待几秒钟,直到连接建立 - 您将在页面上看到绿色 **已连接** 标签。

连接后,单击 **列出工具** 并选择 `get_graph_user_details`。 这将使您能够从 Microsoft Graph 获取当前已验证用户的数据。单击 **运行工具**。

如果一切顺利,您将在响应块中看到您的用户数据,如下所示:
```json
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"businessPhones": [],
"displayName": "您的姓名",
"givenName": null,
"jobTitle": null,
"mail": "您的电子邮件",
"mobilePhone": null,
"officeLocation": null,
"preferredLanguage": null,
"surname": null,
"userPrincipalName": "您的UPN",
"id": "c6b77314-c0ec-44b2-b0bb-2c971a753f0c",
"success": true
}
```
## 反馈和报告问题
如果您遇到任何障碍或有评论,请务必[打开问题](https://github.com/localden/remote-auth-mcp-apim-py/issues)。
连接信息
猜你喜欢
暂无推荐服务器