Token导航 LogoToken导航TokenDH.com
Sts Entraid Single A2a Adkagent MCP Poc logo
AI代理stdio官方级别未说明来源级核验

Sts Entraid Single A2a Adkagent MCP Poc

MCP Server

一个安全的多层AI代理系统,用户身份从前端认证传播到代理层再到资源API,通过三层独立访问控制实现深度防御。

工具数

7

提示词数

0

GitHub Stars

0

资源数

0
AI代理访问控制ClaudeClaude

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

作者 / 组织

sanjay-sts

提供方

sanjay-sts

最后核验

2026/5/17 20:21

快速接入

先看主来源和安装命令,再打开仓库或文档;下面只保留这个条目的关键接入事实。

命令预览

pip install -r requirements.txt

详细介绍

身份感知人工智能代理系统

一个安全的多层人工智能代理系统,用户身份从前端身份验证通过代理层传播到资源API。该架构在三个独立的级别上实施访问控制,提供深度防御。

目录

______________________________________________________________________

系统设计

概述

该系统使用 OAuth 2.0与OpenID连接(OIDC) 对于身份验证和授权,支持多个身份提供商(Microsoft Entra ID和AWS Cognito):

  • 协议:使用PKCE(代码交换证明密钥)的OAuth 2.0授权代码流
  • 令牌格式:由IdP签名的JWT访问令牌,通过JWKS(JSON Web密钥集)验证
  • 前端:使用MSAL.js 3.6(Entra)+AWS Amplify 6(Cognito)进行反应——统一的身份验证提供者
  • 网关:A2A用于代理发现和请求路由的协议服务器
  • 代理:谷歌ADK与克劳德·海库4.5通过LiteLLM(AWS基岩)
  • 工具:提供身份识别软件工具的FastMCP服务器(Graph API+S3)

技术栈

组件技术端口目的
前端React 18+MSAL.js 3.6+AWS Amplify 610003用户身份验证、令牌获取
网关A2A协议(FastAPI+A2A-sdk)10000代理发现、代理级ACL、流媒体
代理谷歌ADK+LiteLLM+Claude Haiku 4.5(基岩)10001LLM编排、工具调用
工具FastMCP(无状态HTTP)10002工具执行、令牌传播
身份Entra ID+AWS Cognito-OAuth 2.0+OIDC,多IdP JWT验证
资源Microsoft Graph API、AWS S3-用户数据、文件、电子邮件、云存储

三层安全模型

级别位置机制强制执行拒绝访问
1.代理人A2A服务器组成员资格,阻止列表auth_middleware用户被阻止或不在允许的组中
2.工具FastMCP基于角色的权限(RBAC)内置身份验证(JWT验证)+ auth=require_role() 装饰师+ UserContextMiddleware令牌无效、未担任角色或角色缺乏工具权限
3.资源Graph APIOAuth作用域Microsoft Graph缺少所需作用域的令牌

______________________________________________________________________

当前状态

工作特点

功能状态注释
入境者身份验证✅ 工作中MSAL.js弹出/静默令牌获取
AWS Cognito身份验证✅ 工作增强托管UI重定向流
自定义API范围✅ 工作api://{client-id}/access_as_user
多IdP令牌验证✅ 工作中Entra v1.0/v2.0+Cognito JWTs
A2A协议✅ 工作代理卡发现、消息/发送
ADK+克劳德·海库4.5✅ 工作通过LiteLLM在AWS基岩上
MCP工具(无状态)✅ 正在工作通过header_provider传递的令牌
多回合对话✅ 工作会话状态保留在ADK中
RBAC执行✅ 工作三层访问控制
海外建筑运营管理局代币交换✅ 工作通过On-Behalf-Of流绘制API图形
S3工具✅ 工作服务器端AWS凭据
X—承担角色✅ 工作端到端角色传播

已知限制

限制影响
前端使用缓冲 /chat/chat/stream一次显示所有响应
内存中的会话服务重新启动时丢失
JWKS缓存永远不会时间失效(A2A)可能会出现过期密钥(未命中时自动清除)
未处理组超龄Entra>记录了150个组,但未提取

______________________________________________________________________

架构图

系统架构

┌─────────────────────────────────────────────────────────────────────────────────────┐
│                                    USER BROWSER                                       │
│  ┌─────────────────────────────────────────────────────────────────────────────────┐ │
│  │                         React Frontend (Port 10003)                              │ │
│  │  ┌──────────────┐    ┌──────────────┐    ┌──────────────────────────────────┐   │ │
│  │  │   MSAL.js    │───▶│ Auth State   │───▶│  Chat Interface                  │   │ │
│  │  │  (Login)     │    │ (Token)      │    │  - Send messages                 │   │ │
│  │  └──────────────┘    └──────────────┘    │  - Display responses             │   │ │
│  │         │                   │            │  - Scope selection               │   │ │
│  │         ▼                   ▼            └──────────────────────────────────┘   │ │
│  │  ┌─────────────────────────────────────────────────────────────────────────┐    │ │
│  │  │              Microsoft Entra ID (OAuth 2.0 + OIDC)                      │    │ │
│  │  │  - Token issuance (custom API scope + Graph scopes)                     │    │ │
│  │  │  - Group claims in token                                                │    │ │
│  │  └─────────────────────────────────────────────────────────────────────────┘    │ │
│  └─────────────────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────────────┘
                                          │
                                          │ HTTP POST + Bearer Token
                                          ▼
┌─────────────────────────────────────────────────────────────────────────────────────┐
│                              A2A Gateway (Port 10000)                                │
│  ┌──────────────────────────────────────────────────────────────────────────────┐   │
│  │                         auth_middleware                                       │   │
│  │  1. Validate JWT signature (JWKS from Entra ID)                              │   │
│  │  2. Check blocklist (BLOCKED_USERS)                                          │   │
│  │  3. Verify group membership (ALLOWED_GROUPS)                                 │   │
│  │  4. Set ContextVar: current_user_claims, current_access_token                │   │
│  └──────────────────────────────────────────────────────────────────────────────┘   │
│                                          │                                           │
│                                          ▼                                           │
│  ┌──────────────────────────────────────────────────────────────────────────────┐   │
│  │                    IdentityAwareAgentExecutor                                 │   │
│  │  1. Extract user claims from ContextVar                                       │   │
│  │  2. Ensure ADK session exists for user                                        │   │
│  │  3. Forward request to ADK Agent                                              │   │
│  │  4. Emit TaskStatusUpdateEvent with response                                  │   │
│  └──────────────────────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────────────────────┘
                                          │
                                          │ HTTP POST + Bearer Token
                                          ▼
┌─────────────────────────────────────────────────────────────────────────────────────┐
│                              ADK Agent (Port 10001)                                  │
│  ┌──────────────────────────────────────────────────────────────────────────────┐   │
│  │                         Session Management                                    │   │
│  │  - InMemorySessionService                                                     │   │
│  │  - Session state: user:access_token, user:email, user:role, user:groups      │   │
│  └──────────────────────────────────────────────────────────────────────────────┘   │
│                                          │                                           │
│                                          ▼                                           │
│  ┌──────────────────────────────────────────────────────────────────────────────┐   │
│  │                    LlmAgent (Claude Haiku 4.5 via LiteLLM)                     │   │
│  │  - Processes user message                                                     │   │
│  │  - Decides which tools to call                                               │   │
│  │  - Formats final response                                                     │   │
│  └──────────────────────────────────────────────────────────────────────────────┘   │
│                                          │                                           │
│                                          ▼                                           │
│  ┌────────────────────────┐    ┌────────────────────────────────────────────────┐   │
│  │    Local Tools         │    │              McpToolset                         │   │
│  │  - get_identity_info   │    │  - header_provider injects Bearer token        │   │
│  │  - check_my_permissions│    │  - Calls FastMCP server                        │   │
│  └────────────────────────┘    └────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────────────────────┘
                                          │
                                          │ HTTP POST + Bearer Token (from header_provider)
                                          ▼
┌─────────────────────────────────────────────────────────────────────────────────────┐
│                              FastMCP Server (Port 10002)                             │
│  ┌──────────────────────────────────────────────────────────────────────────────┐   │
│  │                      FastMCP Built-in Auth (MultiAuth)                        │   │
│  │  1. AzureJWTVerifier (v2.0) — auto-configured from Azure app registration  │   │
│  │  2. JWTVerifier (v1.0 fallback) — for sts.windows.net issuer tokens         │   │
│  │  3. Validates JWT signature, issuer, audience, expiry via JWKS              │   │
│  └──────────────────────────────────────────────────────────────────────────────┘   │
│                                          │                                           │
│                                          ▼                                           │
│  ┌──────────────────────────────────────────────────────────────────────────────┐   │
│  │                      UserContextMiddleware                                    │   │
│  │  1. Detect IdP provider from iss claim (entra/cognito/auth0)                │   │
│  │  2. Extract email, groups from validated token claims                        │   │
│  │  3. Resolve available roles via TomlPolicyEvaluator (permissions.toml)      │   │
│  │  4. Validate X-Assume-Role header against available roles                   │   │
│  │  5. Set ContextVars: current_user_token, current_user_role, current_user_email│  │
│  └──────────────────────────────────────────────────────────────────────────────┘   │
│                                          │                                           │
│                                          ▼                                           │
│  ┌──────────────────────────────────────────────────────────────────────────────┐   │
│  │                      Per-Tool Auth Decorators                                │   │
│  │  1. auth=require_role() checks user role via ContextVar                      │   │
│  │  2. Raises ToolError with [TOOL_DENIAL] prefix on denial                    │   │
│  └──────────────────────────────────────────────────────────────────────────────┘   │
│                                          │                                           │
│                                          ▼                                           │
│  ┌──────────────────────────────────────────────────────────────────────────────┐   │
│  │                              MCP Tools                                        │   │
│  │  - get_user_profile      (all roles)                                         │   │
│  │  - list_files            (admin, developer)                                  │   │
│  │  - send_email            (admin only)                                        │   │
│  │  - delete_resource       (admin only)                                        │   │
│  │  - get_current_time      (admin only)                                        │   │
│  │  - convert_timezone      (admin only)                                        │   │
│  │  - get_time_difference   (admin only)                                        │   │
│  └──────────────────────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────────────────────┘
                                          │
                                          │ (Optional) Graph API calls with user token
                                          ▼
┌─────────────────────────────────────────────────────────────────────────────────────┐
│                              Microsoft Graph API                                     │
│  - /me (User.Read scope)                                                            │
│  - /me/drive/root/children (Files.Read scope)                                       │
│  - /me/sendMail (Mail.Send scope)                                                   │
└─────────────────────────────────────────────────────────────────────────────────────┘

请求流程图

┌──────────┐     ┌──────────┐     ┌──────────┐     ┌──────────┐     ┌──────────┐
│  User    │     │ Frontend │     │   A2A    │     │   ADK    │     │   MCP    │
│ Browser  │     │  React   │     │ Gateway  │     │  Agent   │     │  Server  │
└────┬─────┘     └────┬─────┘     └────┬─────┘     └────┬─────┘     └────┬─────┘
     │                │                │                │                │
     │  1. Login      │                │                │                │
     │───────────────▶│                │                │                │
     │                │ 2. MSAL        │                │                │
     │                │ acquireToken   │                │                │
     │                │───────────────▶│ Entra ID      │                │
     │                │◀───────────────│ (Token)       │                │
     │                │                │                │                │
     │  3. Send msg   │                │                │                │
     │───────────────▶│                │                │                │
     │                │ 4. POST /      │                │                │
     │                │ + Bearer token │                │                │
     │                │───────────────▶│                │                │
     │                │                │ 5. Validate    │                │
     │                │                │    JWT         │                │
     │                │                │ 6. Check       │                │
     │                │                │    groups      │                │
     │                │                │                │                │
     │                │                │ 7. POST /chat  │                │
     │                │                │ + Bearer token │                │
     │                │                │───────────────▶│                │
     │                │                │                │ 8. Store token │
     │                │                │                │    in session  │
     │                │                │                │                │
     │                │                │                │ 9. LLM decides │
     │                │                │                │    tool call   │
     │                │                │                │                │
     │                │                │                │ 10. MCP call   │
     │                │                │                │ + Bearer token │
     │                │                │                │───────────────▶│
     │                │                │                │                │ 11. Validate
     │                │                │                │                │     JWT
     │                │                │                │                │ 12. Check
     │                │                │                │                │     role
     │                │                │                │                │ 13. Execute
     │                │                │                │                │     tool
     │                │                │                │◀───────────────│
     │                │                │                │ 14. Tool result│
     │                │                │                │                │
     │                │                │                │ 15. LLM formats│
     │                │                │                │     response   │
     │                │                │◀───────────────│                │
     │                │                │ 16. Response   │                │
     │                │◀───────────────│                │                │
     │                │ 17. A2A result │                │                │
     │◀───────────────│                │                │                │
     │ 18. Display    │                │                │                │
     │                │                │                │                │

______________________________________________________________________

身份验证流程

系统使用 使用PKCE的OAuth 2.0授权代码流 通过Microsoft Entra ID。MSAL.js 3.6处理前端流——不使用隐式授权。令牌是包含OAuth 2.0/OIDC声明的标准JWT(iss, aud, exp, scp, groups, preferred_username等等),并在每一层使用提供商的JWKS公钥进行验证。

初始身份验证

1. User clicks "Sign In with Microsoft"
2. MSAL.js opens popup to Entra ID login (Authorization Code + PKCE)
3. User authenticates with credentials/MFA
4. Entra ID returns an authorization code to the SPA
5. MSAL.js exchanges the code for tokens (PKCE-secured, no client secret):
   - ID Token (OIDC — user identity claims)
   - Access Token (OAuth 2.0 — with custom API scope + Graph scopes)
6. MSAL.js caches tokens in browser storage
7. Frontend shows authenticated state

请求令牌获取

// Frontend: authConfig.js
const API_SCOPE = `api://${clientId}/access_as_user`;

export const graphScopes = {
  basic: [API_SCOPE, 'User.Read'],
  files: [API_SCOPE, 'User.Read', 'Files.Read'],
  email: [API_SCOPE, 'User.Read', 'Mail.Send'],
  full: [API_SCOPE, 'User.Read', 'Files.Read', 'Mail.Send'],
  destructive: [API_SCOPE, 'User.Read', 'Files.Read', 'Files.ReadWrite.All', 'Mail.Send'],
};

// Token acquisition (cached, no re-prompt unless expired)
const token = await instance.acquireTokenSilent({ scopes, account });

令牌格式和验证

访问令牌是 JWT(JSON Web令牌) 由Entra ID使用RS256签名。每个后端层通过从Microsoft的JWKS端点获取公钥并验证签名、颁发者、受众和到期时间来独立验证Bearer令牌。Entra ID可以发行v1.0代币(发行人: sts.windows.net/{tenant}/)或v2.0令牌(发行者: login.microsoftonline.com/{tenant}/v2.0)--两者都支持。

A2A服务器 --手动JWT验证:

# a2a_server/server.py — manual JWKS fetching, supports v1.0 and v2.0 tokens
JWKS_URIS = [
    f"https://login.microsoftonline.com/{TENANT_ID}/discovery/v2.0/keys",
    f"https://login.microsoftonline.com/{TENANT_ID}/discovery/keys",
    "https://login.microsoftonline.com/common/discovery/keys",
]
VALID_ISSUERS = [
    f"https://login.microsoftonline.com/{TENANT_ID}/v2.0",
    f"https://sts.windows.net/{TENANT_ID}/",
]

MCP 服务器 --FastMCP 3.1内置身份验证 MultiAuth:

# mcp_server/server.py — uses FastMCP's built-in auth providers
# v2.0 verifier (primary)
AzureJWTVerifier(client_id=CLIENT_ID, tenant_id=TENANT_ID, required_scopes=["access_as_user"])

# v1.0 verifier (fallback for sts.windows.net issuer tokens)
JWTVerifier(
    jwks_uri=f"https://login.microsoftonline.com/{TENANT_ID}/discovery/keys",
    issuer=f"https://sts.windows.net/{TENANT_ID}/",
    audience=[CLIENT_ID, f"api://{CLIENT_ID}"],
    required_scopes=["access_as_user"],
)
# Composed via MultiAuth — tries v2.0 first, falls back to v1.0

______________________________________________________________________

多回合对话流程

根据请求重新验证令牌

动作频率缓存?
前端acquireTokenSilent()每个请求是(SWITCHache)
A2A服务器JWT签名验证每个请求JWKS缓存
A2A服务器组成员资格检查每个请求
ADK代理在会话中存储令牌每个请求会话状态
MCP 服务器JWT签名验证每次工具调用JWKS缓存
MCP 服务器角色权限检查每次工具调用

ADK中的会话状态

# Session state stored with user: prefix for persistence
session.state = {
    "user:access_token": "",      # Updated each request
    "user:email": "user@domain.com",
    "user:name": "User Name",
    "user:groups": ["group-id-1", "group-id-2"],
    "user:role": "admin"                      # Derived from groups
}

多转弯示例

Turn 1: "What's my email?"
  ├─ Token validated at A2A (cached JWKS)
  ├─ Session created in ADK
  ├─ Local tool: get_identity_info
  └─ Response: "Your email is user@domain.com"

Turn 2: "What time is it in Tokyo?"
  ├─ Token validated at A2A (same JWKS)
  ├─ Session retrieved (same session_id)
  ├─ Token updated in session state
  ├─ MCP tool: get_current_time
  │   ├─ Token validated at MCP (cached JWKS)
  │   └─ Role check: admin required ✓
  └─ Response: "The time in Tokyo is..."

Turn 3: "List my files"
  ├─ Token validated at A2A
  ├─ Session retrieved
  ├─ MCP tool: list_files
  │   ├─ Token validated at MCP
  │   └─ Role check: admin/developer required ✓
  └─ Response: "Your files are..."

______________________________________________________________________

上下文和身份传递

A2A服务器→ ADK代理

# A2A Server uses ContextVar to pass auth data
current_user_claims: ContextVar[dict] = ContextVar("current_user_claims", default={})
current_access_token: ContextVar[str] = ContextVar("current_access_token", default="")

# Set in auth_middleware
current_user_claims.set(claims)
current_access_token.set(token)

# Read in IdentityAwareAgentExecutor
user_claims = current_user_claims.get()
access_token = current_access_token.get()

# Forward to ADK Agent via HTTP
POST /chat
{
    "message": "user message",
    "user_id": "sub-claim-value",
    "session_id": "session-uuid"
}
Headers: Authorization: Bearer 

ADK代理→ MCP 服务器

# McpToolset uses header_provider for dynamic auth
def mcp_header_provider(readonly_context: ReadonlyContext) -> Dict[str, str]:
    if readonly_context and readonly_context.state:
        access_token = readonly_context.state.get("user:access_token", "")
        if access_token:
            return {"Authorization": f"Bearer {access_token}"}
    return {}

# McpToolset configuration
self.mcp_toolset = McpToolset(
    connection_params=StreamableHTTPConnectionParams(url=MCP_SERVER_URL),
    header_provider=mcp_header_provider,  # Injects token per-request
)

MCP服务器上下文变量

# MCP Server stores validated claims in ContextVar (stateless mode — no ctx.get_state())
current_user_token: ContextVar[str] = ContextVar("current_user_token", default="")
current_user_role: ContextVar[str] = ContextVar("current_user_role", default="none")
current_user_email: ContextVar[str] = ContextVar("current_user_email", default="")

# Set by UserContextMiddleware, read by tools and auth= callables
@mcp.tool(auth=require_role("admin"))
async def get_current_time(timezone: str = "UTC") -> dict:
    user_role = current_user_role.get()
    user_email = current_user_email.get()
    # ... tool logic

______________________________________________________________________

RBAC(基于角色的访问控制)

角色继承

admin      → Full access to all tools
developer  → Access to profile and file tools
viewer     → Access to profile tools only
none       → No tool access (agent-level denied)

组到角色映射(permissions.toml)

角色定义见 permissions.toml (代理人所有,未经授权)。复制自 permissions.example.toml:

# permissions.toml — Agent-owned role assignments
# Group-to-role mapping is the PRIMARY mechanism.
# User-level overrides are optional for exceptions.

[group_rules.entra]
"" = "admin"
"" = "developer"
"" = "viewer"

[group_rules.cognito]
# "platform-admins" = "admin"  # Future: Cognito groups

[group_rules.auth0]
# "admin" = "admin"  # Future: Auth0 roles

[users]
# Optional direct user overrides (case-insensitive email lookup)
# "user@company.com" = { role = "admin" }

[defaults]
unknown_users = "none"

TomlPolicyEvaluator (mcp_server/policy.py)通过文件更改时的热重新加载,从组声明和用户覆盖中解析可用角色。角色优先级:管理员>开发人员>查看器。

角色选择:用户必须设置 X-Assume-Role MCP工具调用的标题。 UserContextMiddleware 根据可用角色验证假定的角色。对于工具列表,将自动使用优先级最高的角色。

备注:A2A服务器仍在使用 GROUP_TO_ROLE 来自env变量(ADMIN_GROUP_ID等等)用于代理级访问控制。MCP服务器使用 permissions.toml 用于工具级RBAC。

工具权限矩阵

工具允许的角色描述
get_user_profile管理员、开发人员、查看器获取Microsoft Graph配置文件(或令牌声明回退)
list_files管理员、开发人员列出OneDrive文件
send_emailadmin通过Graph发送电子邮件
delete_resourceadmin删除资源
get_current_timeadmin获取时区时间
convert_timezoneadmin时区转换
get_time_differenceadmin比较时区偏移

权限执行代码

# MCP Server: Per-tool auth= decorators (require_role only — IdP scope checking removed)
@mcp.tool(auth=require_role("admin", "developer", "viewer"))
async def get_user_profile() -> dict: ...

@mcp.tool(auth=require_role("admin", "developer"))
async def list_files(folder_path: str = "/") -> dict: ...

@mcp.tool(auth=require_role("admin"))
async def send_email(to: str, subject: str, body: str) -> dict: ...

# Auth helper
def require_role(*allowed_roles):
    # Reads current_user_role ContextVar (set by UserContextMiddleware)
    # Raises: "[TOOL_DENIAL] Access denied: Role '...' cannot use this tool. Required roles: [...]"
    ...

拒绝访问示例

No X-Assume-Role header:
  → [ROLE_SELECTION] Role selection required. Set X-Assume-Role header to one of: ['admin']

Viewer tries to list files:
  → [TOOL_DENIAL] Access denied: Role 'viewer' cannot use this tool. Required roles: ['admin', 'developer']

Developer tries to send email:
  → [TOOL_DENIAL] Access denied: Role 'developer' cannot use this tool. Required roles: ['admin']

User tries to assume a role they don't have:
  → [TOOL_DENIAL] Cannot assume role 'admin'. Available roles: ['developer']

No-group user (not in permissions.toml):
  → [TOOL_DENIAL] No roles available for user@domain.com. Contact admin to assign group membership.

User without groups at A2A gateway:
  → 403 {"error": "access_denied", "denial_level": "agent", "denial_reason": "no_group_membership"}

Blocked user:
  → 403 {"error": "access_denied", "denial_level": "agent", "denial_reason": "blocked_user"}

______________________________________________________________________

API 参考

A2A服务器(端口10000)

代理卡发现

GET /.well-known/agent-card.json

答复:

{
  "name": "Identity-Aware AI Agent",
  "description": "An AI agent with Entra ID authentication...",
  "url": "http://localhost:10000/",
  "version": "1.0.0",
  "capabilities": {"streaming": true},
  "skills": [...]
}

发送消息(A2A协议)

POST /
Authorization: Bearer 
Content-Type: application/json

{
  "jsonrpc": "2.0",
  "method": "message/send",
  "params": {
    "message": {
      "messageId": "msg-123",
      "role": "user",
      "parts": [{"type": "text", "text": "What time is it?"}]
    }
  },
  "id": "req-123"
}

答复:

{
  "id": "req-123",
  "jsonrpc": "2.0",
  "result": {
    "id": "task-uuid",
    "kind": "task",
    "status": {
      "state": "completed",
      "message": {
        "kind": "message",
        "role": "agent",
        "parts": [{"kind": "text", "text": "The current time is..."}]
      }
    }
  }
}

健康检查

GET /health

安全上下文

GET /me
Authorization: Bearer 

答复:

{
  "user": { "email": "user@domain.com", "name": "User Name", "oid": "..." },
  "security": {
    "role": "developer",
    "groups": ["group-id-1"],
    "group_names": { "group-id-1": "developer" },
    "token_scopes": ["User.Read", "Files.Read"],
    "token_expiry": 1741363200,
    "issuer": "https://login.microsoftonline.com/{tenant}/v2.0"
  },
  "permissions": {
    "get_user_profile": true, "list_files": true, "send_email": false,
    "delete_resource": false, "get_current_time": false,
    "convert_timezone": false, "get_time_difference": false
  },
  "tool_scopes": {
    "get_user_profile": ["User.Read"], "list_files": ["Files.Read"],
    "send_email": ["Mail.Send"], "delete_resource": ["Files.ReadWrite.All"],
    "get_current_time": [], "convert_timezone": [], "get_time_difference": []
  }
}

ADK代理(端口10001)

创建会话

POST /session
Authorization: Bearer 
Content-Type: application/json

{
  "user_id": "user-sub-claim",
  "user_info": {
    "email": "user@domain.com",
    "name": "User Name",
    "groups": ["group-id-1"]
  }
}

答复:

{"session_id": "session-uuid"}

聊天

POST /chat
Authorization: Bearer 
Content-Type: application/json

{
  "message": "What's my email?",
  "user_id": "user-sub-claim",
  "session_id": "session-uuid"
}

答复:

{
  "response": "Your email is user@domain.com",
  "session_id": "session-uuid"
}

MCP服务器(端口10002)

MCP端点

POST /mcp
Authorization: Bearer 
Content-Type: application/json

# Standard MCP protocol messages

可用工具

工具参数返回
get_user_profile(无)来自Graph或令牌声明的用户配置文件
list_filesfolder_path?: string文件名列表
send_emailto, subject, body发送状态
delete_resourceresource_id删除状态
get_current_timetimezone?: string带纪元的时间信息
convert_timezonetime_str, from_timezone, to_timezone转换时间
get_time_differencetimezone1, timezone2偏移差

______________________________________________________________________

安装指南

先决条件

  • Python 3.10+
  • Node.js 18+
  • Microsoft Entra ID租户
  • Anthropic API密钥(用于Claude)

1.微软Entra ID配置

  1. 在中创建应用程序注册 Entra管理中心
  2. 配置平台:单页应用

- 重定向URI: http://localhost:10003, http://localhost:10003/redirect

  1. 公开API:

- 添加范围: access_as_user - 应用程序ID URI: api://{client-id}

  1. API权限:

- openid, profile, User.Read, Files.Read, Mail.Send

  1. 令牌配置:

- 添加组声明(安全组)

  1. 创建安全组:

- 管理员组、开发人员组、查看器组

2.环境设置

# Backend (.env)
cp .env.example .env

# Required variables:
ENTRA_CLIENT_ID=
ENTRA_TENANT_ID=
ADMIN_GROUP_ID=
DEVELOPER_GROUP_ID=
VIEWER_GROUP_ID=
ANTHROPIC_API_KEY=

# Frontend (frontend/.env)
cd frontend && cp .env.example .env

REACT_APP_ENTRA_CLIENT_ID=
REACT_APP_ENTRA_TENANT_ID=

# MCP Permissions (group-to-role mapping)
cp permissions.example.toml permissions.toml
# Edit permissions.toml with your Entra ID security group GUIDs

3.安装依赖项

# Backend
pip install -r requirements.txt
# or with uv:
uv pip install -r requirements.txt

# Frontend
cd frontend && npm install

4.运行服务

# Terminal 1: MCP Server
uv run python mcp_server/server.py

# Terminal 2: ADK Agent
uv run python adk_agent/agent.py

# Terminal 3: A2A Gateway
uv run python a2a_server/server.py

# Terminal 4: Frontend
cd frontend && npm start

5.访问申请

  • 前端:http://localhost:10003
  • A2A网关:http://localhost:10000
  • 代理卡:http://localhost:10000/.well-已知/代理卡.json

______________________________________________________________________

安全测试仪表板

前端包括一个全面的安全测试仪表板,用于测试和可视化三层访问控制系统。

仪表板组件

组件位置目的
安全上下文面板左侧边栏显示角色、组、范围、令牌到期倒计时
令牌检查器左侧边栏(可折叠)解码JWT标头/有效载荷以供显示
RBAC测试矩阵左侧边栏一键式测试网格,带通过/失败跟踪
对话选项卡主区域多选项卡聊天,每个选项卡范围选择(最多4个)
审核日志主区域(底部)拒绝分类的请求历史记录
拒绝指示器内联徽章颜色编码的拒绝层:代理(红色)、工具(橙色)、资源(紫色)
帐户切换器标题支持多帐户以测试不同角色

拒绝分类

拒绝被自动分为四个等级:

检测者示例
代理http401/403+ denial_level 在响应正文中用户不在任何组中
工具[TOOL_DENIAL] 响应文本中的标记查看器正在尝试 list_files
RESOURCE响应文本中的Graph API 403Graph权限不足

前端文件结构

frontend/src/
  App.js                      # Dashboard layout shell
  App.css                     # Dark theme styles
  authConfig.js               # MSAL config + scope presets (basic, files, email, full, destructive)
  index.js                    # MSAL provider setup
  components/
    AuthStatus.js             # Multi-account switcher dropdown
    LoginPrompt.js            # Sign-in prompt
    SecurityContextPanel.js   # Role, groups, scopes, expiry countdown
    TokenInspector.js         # JWT decoder display
    ConversationTabs.js       # Multi-tab chat with per-tab scope
    ChatInterface.js          # Chat with denial tagging and latency tracking
    RBACTestMatrix.js         # One-click test grid
    AuditLog.js               # Request history table
    DenialIndicator.js        # Color-coded denial badge
  utils/
    tokenDecoder.js           # JWT base64url decode helper
    denialClassifier.js       # HTTP status + response text → denial tier
    testScenarios.js          # Predefined test prompts with expected outcomes

______________________________________________________________________

测试

运行测试

# With services running
uv run pytest tests/test_access_control.py -v

手动测试

  1. 使用管理员组中的用户登录
  1. 测试:“我的电子邮件是什么?”→ 应该可以
  1. 测试:“东京现在几点了?”→ 应该工作(仅限管理员)
  1. 测试:“列出我的文件”→ 应该可以
  1. 使用查看器组中的用户登录
  1. 测试:“我的电子邮件是什么?”→ 应该可以
  1. 测试:“东京现在几点了?”→ 应该失败(仅限管理员)

检查日志

# All logs in logs/ directory
tail -f logs/a2a_server.log
tail -f logs/adk_agent.log
tail -f logs/mcp_server.log

______________________________________________________________________

文档链接

______________________________________________________________________

许可证

麻省理工学院

目录标签

目录标签

AI代理访问控制Claude本地部署身份认证OAuth2.0RBAC

支持客户端

Claude

接入字段

传输方式(transport,传输协议)

stdio

鉴权方式(authType,认证方式)

oauth

工具数量(toolCount,工具数)

7

资源数量(resourceCount,资源数)

0

提示词数量(promptCount,提示词数)

0

权限和风险

stdiooauth部署方式未说明

接入前请确认传输方式、认证方式和部署位置,并根据实际工具能力限制访问范围。

安装前确认

不要直接授予不必要的文件、网络或账号权限;先核对安装命令和配置内容。

来源信息

继续浏览同类 MCP