跳至主要內容

如何为Spring AI MCP Server提供OAuth2认证

程序猿DD原创Spring AISpring AIOAuth2MCP大约 5 分钟

如何为Spring AI MCP Server提供OAuth2认证

Spring AI 提供了对模型上下文协议open in new window(简称 MCP)的支持,该协议允许人工智能模型以结构化的方式与外部工具和资源进行交互并访问它们。

借助 Spring AI,开发人员只需几行代码就可以创建自己的 MCP 服务器,并向人工智能模型公开功能。

MCP 中的授权与安全

MCP 服务器可以使用标准输入输出(STDIO)传输方式在本地运行。要将 MCP 服务器暴露到外部,它必须公开一些标准的 HTTP 端点。虽然私人使用的 MCP 服务器可能不需要严格的身份验证,但企业部署需要对暴露的端点进行完备的安全和权限管理。上周发布的最新版本的 MCP 规范(2025 年 3 月 26 日)open in new window解决了这一挑战。它利用广泛使用的OAuth2 框架open in new window,为确保客户端与服务器之间的通信安全奠定了基础。

虽然我们不会在这篇博客文章中对 OAuth2 进行全面回顾,但快速复习一下可能会很有用。在该规范草案中,MCP 服务器既是资源服务器,也是授权服务器。

作为资源服务器,它通过检查 “Authorization” 标头对传入的请求进行授权检查。该标头必须包含一个 OAuth2 “access_token”(访问令牌),这是一个表示客户端 “权限” 的字符串。该令牌可以是 JSON Web Token(JWT),也可以是一个本身不携带信息的不透明字符串。如果令牌缺失或无效(格式错误、过期、接收方错误等),资源服务器将拒绝该请求。使用这些令牌,一个典型的请求可能如下所示:

curl https://mcp.example.com/sse -H "Authorization: Bearer <有效的访问令牌>"

作为授权服务器,MCP 服务器还必须能够以安全的方式为客户端颁发 “access_token”(访问令牌)。在颁发令牌之前,服务器将验证客户端的凭据,在某些情况下,还会验证试图访问服务器的用户身份。授权服务器将决定令牌的属性:有效期、作用域、目标受众等。

使用 Spring Security 和 Spring Authorization Server,我们可以轻松地将这两种功能添加到现有的 Spring MCP 服务器中。

包含 MCP 客户端和 MCP 服务器的 OAuth2 示意图

为 MCP Server 添加 OAuth2 支持

在这个示例中,我们将为一个示例 MCP 服务器添加 OAuth 2 支持,该服务器是我们 Spring AI 示例仓库中的“天气” MCP 工具open in new window。我们不会探讨交互的客户端方面,只确保我们的服务器能够颁发令牌并验证它们。

首先,我们在 pom.xml 中导入所需的 Spring Boot 启动器:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>
</dependency>

然后,我们在 application.properties 中配置一个 OAuth2 客户端,以便我们可以请求访问令牌:

spring.security.oauth2.authorizationserver.client.oidc-client.registration.client-id=mcp-client
spring.security.oauth2.authorizationserver.client.oidc-client.registration.client-secret={noop}secret
spring.security.oauth2.authorizationserver.client.oidc-client.registration.client-authentication-methods=client_secret_basic
spring.security.oauth2.authorizationserver.client.oidc-client.registration.authorization-grant-types=client_credentials

这是最简单的客户端。我们可以通过发送 POST 请求直接与授权服务器交互,无需浏览器,并使用硬编码的凭据 mcp-client / secret

最后一步是启用授权服务器和资源服务器功能。我们通过为安全功能创建一个配置类(例如 SecurityConfiguration)来实现这一点,在该类中我们公开一个 SecurityFilterChain bean:

import static org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer.authorizationServer;

@Configuration
@EnableWebSecurity
class SecurityConfiguration {

	@Bean
	SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		return http.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
			.with(authorizationServer(), Customizer.withDefaults())
			.oauth2ResourceServer(resource -> resource.jwt(Customizer.withDefaults()))
			.csrf(CsrfConfigurer::disable)
			.cors(Customizer.withDefaults())
			.build();
	}

}

这个过滤器链将执行以下多项操作:

  • 确保每个请求都经过身份验证。有了这一点,我们的 MCP 服务器将只允许带有 “access_token”(访问令牌)的请求。
  • 启用 Spring Authorization Server 和 Spring Resource Server。
  • 关闭跨站请求伪造(CSRF)防护。MCP 服务器不是为基于浏览器的交互而设计的,不需要 CSRF 防护。
  • 启用跨域资源共享(CORS)支持,这样我们就可以使用 MCP 检查器对服务器进行演示。

有了这些设置,我们的应用程序就得到了保护,只会接受带有访问令牌的请求。否则,请求将被拒绝,并返回 HTTP 401 Unauthorized(未经授权)错误。例如:

curl http://localhost:8080/sse --fail-with-body
#
# 响应:
#
# curl: (22) The requested URL returned error: 401

要使用我们的 MCP 服务器,我们首先需要获取一个访问令牌。我们使用 client_credentials 这种 OAuth2 授权类型,它用于 “机器对机器” 或 “服务账户” 场景:

curl -XPOST http://localhost:8080/oauth2/token --data grant_type=client_credentials --user mcp-client:secret
#
# 响应:
#
# {"access_token":"<你的访问令牌>","token_type":"Bearer","expires_in":299}%

复制 access_token 的值。它以字母 “ey” 开头。现在我们可以使用这个访问令牌发出请求,并且这些请求应该会成功。例如,使用 curl,你可以将 YOUR_ACCESS_TOKEN 替换为你上面复制的值:

curl http://localhost:8080/sse -H"Authorization: Bearer YOUR_ACCESS_TOKEN"
#
# 响应:
#
# id:918d5ebe-9ae5-4b04-aae8-c1ff8cdbb6e0
# event:endpoint
# data:/mcp/message?sessionId=918d5ebe-9ae5-4b04-aae8-c1ff8cdbb6e0

0.6.0 版本起,也可以直接在 MCP 检查器open in new window中使用访问令牌。只需启动检查器,然后将访问令牌粘贴到左侧菜单的 “Authentication > Bearer”(身份验证 > 承载令牌)字段中。然后点击 “Connect”(连接):你应该能够进行 MCP 调用。

MCP检查器

如果你想自己运行这个示例,可以查看 spring-ai-examples 仓库中的示例代码open in new window

如果您学习过程中如遇困难?可以加入我们超高质量的Spring技术交流群open in new window,参与交流与讨论,更好的学习与进步!更多Spring专题技术分享点击直达!open in new window,欢迎收藏与转发支持!

上次编辑于:
贡献者: 程序猿DD