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

本文详细介绍了如何使用Microsoft Entra ID实现安全的MCP OAuth桌面客户端,包括MCP服务器的构建、OAuth访问令牌的获取、以及客户端与服务器之间的安全通信机制。

使用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服务器公开的函数。服务器是一个简单的ASP.NET Core应用程序,实现了MCP服务器API。

MCP服务器

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

MCP桌面OAuth客户端

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

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中使用Bearer令牌设置Authorization标头。此令牌在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
24
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;
}

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

注意事项

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

链接

标准、草案标准

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