首页 / 文章 / 实用提示:Spring AI 实战指南——使用 OAuth 保护 MCP 服务器安全

实用提示:Spring AI 实战指南——使用 OAuth 保护 MCP 服务器安全

《实用笔记》操作指南:Spring AI 实战方案——利用 OAuth 保护 MCP 服务器:为采用该模式的团队提供契约、校验规则以及可直接插入的代码片段。

1607 词

以下笔记为“Spring AI Recipe:使用OAuth保护MCP服务器”提供了一条实用的实施路径。重点在于契约、校验以及可直接插入的代码占位符,而非激励性描述。 在完成概览阶段时,首先明确契约内容:所需输入、成功信号以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 将配置信息置于应用程序代码之外。环境文件、密钥存储以及功能开关应集中存放于一个位置,以便操作人员无需查看整个系统结构即可进行审计。

创建授权服务器

将“创建授权服务器”这一阶段视为可度量的对象来处理,效果最佳。在扩大范围之前,需记录一份理想的操作流程、一个故障案例以及回滚说明。同时文档化正常处理路径和恢复路径。重试机制、人工审核环节以及死信处理都属于产品功能的一部分,而非后续需要补充的内容。应提供具有明确结构规范和清晰副作用标识的工具,这样主机才能在自动批准之前知道哪些调用会改变系统状态。

implementation 'org.springaicommunity:mcp-authorization-server:0.1.14'
@Configuration
@EnableWebSecurity
public class SecurityConfig {

  @Bean
  SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    return http
        .authorizeHttpRequests(auth ->
            auth.anyRequest().authenticated())
        .formLogin(withDefaults())
        .with(
            McpAuthorizationServerConfigurer.mcpAuthorizationServer(),
            withDefaults())
        .build();
  }

}
spring:
  application:
    name: recipes-authorization-server
  security:
    oauth2:
      authorizationserver:
        client:
          default-client:
            token:
              access-token-time-to-live: 1h
            registration:
              client-id: "myclient"
              client-secret: "{noop}mysecret"
              client-authentication-methods:
                - "client_secret_basic"
              authorization-grant-types:
                - "authorization_code"
              redirect-uris:
                - "http://localhost:6274/oauth/callback"
                - "http://127.0.0.1:6274/oauth/callback"
              scopes:
                - general-access
                - meteorology
                - administration
    user:
      name: craig
      password: letmein

server:
  port: 9999

保护 MCP 服务器安全

将“保护 MCP 服务器安全”这一环节视为可度量的工作对象来处理效果最佳。在扩大范围之前,先记录一份理想的操作流程、一个故障案例以及回滚说明。 优先使用小型且可测试的单元,而非庞大的脚本。当某个步骤出现故障时,故障应指向单一的责任模块,而非复杂的流程链。 提供具有明确结构规范和清晰副作用标注的工具。主机需要在自动批准之前知道哪些调用会修改状态。

implementation 'org.springaicommunity:mcp-server-security:0.1.14'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:9999
@Configuration
@EnableWebSecurity
class McpSecurityConfig {

  @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
  private String issuerUrl;

  @Bean
  SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    return http
        .authorizeHttpRequests(auth ->
            auth.anyRequest().authenticated())
        .with(
            McpServerOAuth2Configurer.mcpServerOAuth2(),
            (mcpAuthorization) -> {
              mcpAuthorization.authorizationServer(issuerUrl);
            }
        )
        .build();
  }

}

测试 MCP 服务器

将“测试 MCP 服务器”这一阶段视为可度量的工作面,效果最佳。在扩大范围之前,需记录一份理想运行示例、一个失败案例以及回滚说明。 应将此阶段视为输入与已验证输出之间的契约。为相关成果命名,明确成功标准,杜绝默许的半完成状态。 需提供具有严格结构定义和明确副作用标识的工具。主机在自动批准之前必须清楚哪些调用会修改状态。 将“测试 MCP 服务器”这一阶段视为可度量的工作面,效果最佳。在扩大范围之前,需记录一份理想运行示例、一个失败案例以及回滚说明。 应将配置置于应用程序代码之外。环境文件、密钥存储及功能开关应集中存放,以便操作人员无需查看整个系统结构即可进行审计。

保护单个工具的安全

在“保障单个工具安全”阶段,应在修改代码之前明确输入参数、该步骤的负责人以及结束标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 需同时记录正常流程与故障恢复流程。重试机制、人工审核环节以及错误处理都是产品本身的组成部分,而非后续需要补充的功能。 在网关处进行身份验证,在数据层进行重新授权。仅凭承载令牌并不能作为租户边界。

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
class SecurityConfig {

  @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
  private String issuerUrl;

  @Bean
  SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    return http
        .authorizeHttpRequests(auth -> {
          auth.requestMatchers("/mcp").permitAll();
          auth.anyRequest().authenticated();
        })
        .with(
            McpServerOAuth2Configurer.mcpServerOAuth2(),
            (mcpAuthorization) -> {
              mcpAuthorization.authorizationServer(issuerUrl);
            }
        )
        .build();
  }

}
@PreAuthorize("hasAuthority('SCOPE_meteorology')")
@McpTool(
    name = "get-weather-for-zipcode",
    description = "Gets the weather for a given zipcode",
    annotations = @McpTool.McpAnnotations(
        openWorldHint = false,
        destructiveHint = false,
        idempotentHint = true))
Weather getWeatherForZipcode(
    @McpToolParam(description = "The zipcode to get weather for")
    String zipcode) {
  var context = SecurityContextHolder.getContext();
  var username = context.getAuthentication().getName();
  return new Weather(
      zipcode,
      "Raining cats and dogs",
      78.0f,
      username);
}

操作检查清单

在制定操作检查清单时,需明确代码修改前的输入参数、各步骤的负责人以及完成标准。操作人员应能够从已知的检查点重新执行相应步骤,而无需猜测隐藏状态。

在功能结果旁记录处理时间以及令牌或查询成本。提前了解成本情况,可避免在系统从演示环境切换到共享环境时出现意外费用。

在网关处进行身份验证,在数据层再次授权。仅凭承载令牌并不能作为租户边界。

编写简短的操作手册:说明如何轮换密钥、如何清空队列、以及如何回滚上一次的数据导入操作。

将配置信息与应用程序代码分开存放。环境文件、密钥存储和功能标志应集中管理,以便操作人员无需查看整个系统结构即可进行审计。

在网关处进行身份验证,在数据平面处重新授权。仅凭承载令牌并不能构成租户边界。

在升级技术栈之前,先冻结各版本,为关键流程记录完整日志,并明确回滚步骤。共享环境需要设置速率限制、进行租户检查,同时指定专人负责密钥轮换。与其追求花哨的一次性演示,不如注重扎实的可靠性。

关于01496ca9e17e的批量说明:请将提供商密钥存放在仓库之外,设定单会话令牌上限,并将日志与评估用配置文件放在一起,以便后续模型更换时保持对比一致性。

在强化措施的第0阶段,应在修改代码之前明确输入参数、该步骤的负责人以及完成标准。操作人员应能够从已知的检查点重新执行该步骤,而无需猜测隐藏状态。应将此阶段视为输入与验证后输出之间的契约:为相关成果命名,定义成功判定标准,并拒绝默许部分完成的情况。

强化措施细节0/819:需记录该措施的耗时、错误类型以及令牌消耗情况,然后依据固定的评估标准而非主观判断来决定是否保留该变更。

在处理强化措施的第一阶段时,首先写下相关约定:所需的输入参数、成功信号以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改始终符合规范。 应将配置信息与应用程序代码分开。环境文件、密钥存储以及功能开关应集中存放于一个位置,这样操作人员无需查看整个系统结构即可进行审计。

强化措施细节 1/819:针对该措施记录墙钟时间、错误类型以及令牌消耗情况,然后依据固定的评估标准而非个人经验来决定是否保留该变更。

将强化措施的第二阶段视为可度量的对象来处理效果最佳。在扩大范围之前,先记录一份理想的运行日志、一个失败案例以及回滚说明。 相比庞大的脚本,更应采用小型且可测试的单元。当某个步骤出现故障时,故障原因应能明确指向某个具体的责任模块,而非整个复杂的流程。

强化措施细节2/819:为该记录测量运行时间、错误类型以及代币消耗情况,然后依据固定的问题集而非个人经验来判断是否保留该变更。

在强化措施的第3阶段,应在修改代码之前明确输入参数、该步骤的负责人以及完成标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。应在功能结果旁记录运行时间以及代币或查询成本。提前了解成本情况,可避免在从演示环境过渡到共享环境时出现意外费用。

强化措施细节3/819:为该记录测量运行时间、错误类型以及代币消耗情况,然后依据固定的问题集而非个人经验来判断是否保留该变更。

在处理强化措施的第4阶段时,首先写下相关契约:所需的输入参数、成功信号以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改始终符合要求。

同时记录正常流程和故障恢复流程。重试机制、人工审核环节以及错误处理方式都是产品本身的组成部分,而非后续才添加的完善措施。

强化措施的第4/819条细节要求:先测量该环节的耗时、错误类型以及令牌消耗情况,再依据固定的评估标准而非个人经验来决定是否保留该变更。

将强化措施的第5阶段视为可量化的目标面来处理效果最佳。在扩大范围之前,先记录一份理想的操作示例、一个故障案例以及回滚说明。

要把这一阶段视为输入参数与验证后输出结果之间的契约。为相关文档命名,明确成功判定标准,杜绝默许部分完成的情况。

强化措施细节5/819:记录该条说明的运行时间、错误类型以及令牌消耗情况,然后依据固定的问题集而非个人经验来判断是否保留该变更。

对于强化措施的第6阶段,在修改代码之前需明确输入参数、该步骤的负责人以及完成标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。配置应置于应用程序代码之外,环境文件、密钥存储以及功能标志应集中存放于一个操作人员可以审核的位置,无需查看整个系统结构。

强化措施细节6/819:记录该条说明的运行时间、错误类型以及令牌消耗情况,然后依据固定的问题集而非个人经验来判断是否保留该变更。