使用OAuth与Entra ID实现安全的MCP OAuth桌面客户端

本文详细介绍了如何使用Microsoft Entra ID实现一个安全的MCP OAuth桌面客户端,包括客户端应用如何通过公共OpenID Connect客户端获取委托访问令牌并与受保护的MCP服务器进行交互。

使用OAuth与Entra ID实现安全的MCP OAuth桌面客户端

本文演示了如何使用 Microsoft Entra ID 实现一个安全的 MCP OAuth 桌面客户端。MCP 服务器是使用 ASP.NET Core 构建的,并通过 Microsoft Entra ID 进行安全保护。MCP 客户端是一个 .NET 控制台应用程序,它必须获取一个 OAuth 访问令牌才能与 MCP 服务器交互。

代码仓库: https://github.com/damienbod/McpSecurity

配置

开发了一个客户端应用程序,用于验证和与受 Microsoft Entra ID 保护的 MCP 服务器交互。它使用 Azure OpenAI,并通过一个公共 OpenID Connect 客户端获取委托访问令牌。然后,应用程序调用 MCP 服务器公开的函数。服务器是一个简单的实现了 MCP Server API 的 ASP.NET Core 应用程序。

MCP 服务器

客户端使用了前文“使用 OAuth 和 Entra ID 实现安全的 MCP 服务器”中的 MCP 服务器。它只接受来自特定租户的 Microsoft Entra ID 的委托访问令牌。

MCP 桌面 OAuth 客户端

使用 Microsoft.Identity.Client Nuget 包来实现公共 OpenID Connect 客户端。作为桌面应用,或者说本演示中使用的控制台应用程序无法保存秘密,因此需要一个公共客户端,并且该客户端必须使用基于用户的委托访问令牌。使用带有 PKCE 的 OpenID Connect 授权码流程进行身份验证,并且客户端必须使用 Web 浏览器来验证用户。此类应用无法使用应用程序到应用程序的服务,我们的信任等级较低。

SignInUserAndGetTokenUsingMSAL 方法用于实现用户身份验证。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private static async Task<string> SignInUserAndGetTokenUsingMSAL(
    PublicClientApplicationOptions configuration, string[] scopes)
{
    string authority = string.Concat(configuration.Instance, configuration.TenantId);
    
    // 通过构建公共客户端应用程序来初始化 MSAL 库
    application = PublicClientApplicationBuilder.Create(configuration.ClientId)
                    .WithAuthority(authority)
                    .WithDefaultRedirectUri()
                    .Build();
    
    AuthenticationResult result;
    try
    {
        var accounts = await application.GetAccountsAsync();
        result = await application.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
         .ExecuteAsync();
    }
    catch (MsalUiRequiredException ex)
    {
        result = await application.AcquireTokenInteractive(scopes)
         .WithClaims(ex.Claims)
         .ExecuteAsync();
    }
    
    return result.AccessToken;
}

CreateMcpTransportAsync 方法使用 Microsoft Entra ID 客户端获取访问令牌,并在 HttpClient 的 Authorization 头中设置 Bearer 令牌。该令牌将在 MCP 服务器上进行验证。服务器期望的是一个带有 “mcp:tools” scp 声明的委托访问令牌。不接受应用程序访问令牌。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private static PublicClientApplicationOptions? appConfiguration = null;
// MSAL 公共客户端应用
private static IPublicClientApplication? application;

public static async Task<IClientTransport> CreateMcpTransportAsync(HttpClient httpClient, IConfigurationRoot configuration)
{
    appConfiguration = configuration.Get<PublicClientApplicationOptions>();
    string[] scopes = ["api://96b0f495-3b65-4c8f-a0c6-c3767c3365ed/mcp:tools"];
    
    // 使用 MSAL 登录用户并获取 MS Graph 的访问令牌
    var accessToken = await SignInUserAndGetTokenUsingMSAL(appConfiguration!, scopes);
    
    httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
    
    var httpMcpServer = configuration["HttpMcpServerUrl"];
    var transport = new SseClientTransport(new()
    {
        Endpoint = new Uri(httpMcpServer!),
        Name = "MCP Desktop Client",
    }, httpClient);
    
    return transport;
}

当应用程序启动时,控制台应用程序会打开浏览器进行身份验证。

注意事项

在此设置中,全程强制使用用户委托访问令牌。无法使用应用程序到应用程序的安全性。MCP 服务器作为远程服务器集成到客户端应用程序中。此设置中未使用 DCR,也不应使用 DCR。信任是支持 DCR 的主要问题。安全性仍可进一步提高,并且存在一些关于此问题的有趣的 OAuth 开放议题。

相关链接

标准、草案标准

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计