返回市场
a2a-MCP带安全功能服务器

a2a-MCP带安全功能服务器

作者:vishalmysore2 星标更新:2025-05-29

项目介绍

A2A 和 MCP 安全集成与 Spring

本项目演示了如何使用 Spring Security 来保护您的 Agent-to-Agent (A2A) 和 Model Context Protocol (MCP) 服务器。它提供了 A2A Java 的代理框架与 Spring 强大安全机制之间的无缝集成。

概述

A2A Java 是一个用于构建基于代理系统的强大框架,而 MCP(模型上下文协议)则允许与各种AI模型进行交互。本项目展示了如何实现以下功能:

  1. 使用基于角色的访问控制来保护代理操作。
  2. 将 Spring Security 与 A2A Java 注解进行集成。
  3. 处理人类用户和AI代理的身份验证。

A2A 安全演示

功能

  • 基于角色的访问控制(USER 和 ADMIN 角色)
  • 注解式安全(@PreAuthorize)
  • 与现有 A2A Java 代理的无缝集成
  • 支持多种客户端实现(Python,Java)
  • 服务器默认启动在 7860 端口,您可以在 application.properties 文件中将其更改为 8080
@Log
@Service
@Agent(groupName = "car booking", groupDescription = "与汽车预订相关的操作")
public class CarBookingAgent {

    @PreAuthorize("hasRole('USER')")
    @Action(description = "根据给定详情预订汽车")
    public String bookCar(String carType, String pickupLocation, String dropLocation) {
        log.info("正在预订类型为:" + carType +
                ",取车地点:" + pickupLocation +
                ",还车地点:" + dropLocation);
        return "已预订类型为 " + carType + " 的汽车,从 " + pickupLocation + " 到 " + dropLocation;
    }

    @PreAuthorize("hasRole('ADMIN')")
    @Action(description = "取消汽车预订")
    public String cancelCarBooking(String bookingId) {
        log.info("正在取消预订ID为:" + bookingId + " 的汽车预订");
        return "预订ID为 " + bookingId + " 的汽车预订已被取消";
    }

    // 此操作是公开的,不需要任何角色
    @Action(description = "获取预订状态")
    public String getBookingStatus(String bookingId) {
        return "预订ID为 " + bookingId + " 的状态已确认";
    }
}

测试 A2A 客户端

让我们测试代理卡是如何根据其角色暴露给客户端的。

使用用户角色进行测试

curl -u user:password http://localhost:7860/.well-known/agent.json

这将只返回这些操作

{"name":"Car Booking Agent","description":"此代理提供汽车预订的能力,允许用户预订汽车、检查预订状态、查看可用汽车类型并获取定价信息。","url":"http://vishal:7860","provider":{"organization":"Car Rentals Inc.","url":"https://example.com"},"version":"1.0.0","documentationUrl":"https://example.com/docs/car-booking-agent","capabilities":{"streaming":true,"pushNotifications":true,"stateTransitionHistory":true},"authentication":{"schemes":["ApiKey"],"credentials":"Basic","valid":true,"bearerAuth":false,"basicAuth":false},"defaultInputModes":["Text","Voice"],"defaultOutputModes":["Text","Voice"],"skills":[{"id":"bookCar","name":"Book Car","description":"允许用户从可用选项中预订汽车。","tags":["booking","car rental","transportation"],"examples":["预订明天的轿车","周末预订SUV"],"inputModes":["Text","Voice"],"outputModes":["Text","Voice"]},{"id":"getBookingStatus","name":"Get Booking Status","description":"允许用户检查他们的汽车预订状态。","tags":["status","booking"],"examples":["我的预订状态是什么?","检查今天的预订状态"],"inputModes":["Text","Voice"],"outputModes":["Text","Voice"]},{"id":"listCarTypes","name":"List Car Types","description":"提供可用于预订的汽车类型列表。","tags":["list","car types","available cars"],"examples":["有哪些可用的汽车类型?","显示汽车列表"],"inputModes":["Text","Voice"],"outputModes":["Text","Voice"]},{"id":"getCarPricing","name":"Get Car Pricing","description":"提供不同汽车类型的定价信息。","tags":["pricing","cost","car rental"],"examples":["轿车的价格是多少?","租用SUV需要多少钱?"],"inputModes":["Text","Voice"],"outputModes":["Text","Voice"]}]}

不使用角色进行测试

curl http://localhost:7860/.well-known/agent.json
{"name":"Car Booking Agent","description":"此代理提供与汽车预订相关的能力,包括检查预订状态、列出汽车类型和检索汽车定价。","url":"http://vishal:7860","provider":{"organization":"Car Rentals Inc.","url":"https://example.com"},"version":"1.0.0","documentationUrl":"https://example.com/docs/car-booking-agent","capabilities":{"streaming":true,"pushNotifications":true,"stateTransitionHistory":false},"authentication":{"schemes":["ApiKey"],"credentials":"Basic","valid":true,"bearerAuth":false,"basicAuth":false},"defaultInputModes":["text","voice"],"defaultOutputModes":["text","voice"],"skills":[{"id":"car_booking","name":"Car Booking","description":"允许用户预订汽车、检查预订状态并检索定价信息。","tags":["car","booking","transportation"],"examples":["从机场预订一辆轿车","检查我的预订状态","列出可用的SUV","获取紧凑型汽车的定价"],"inputModes":["text","voice"],"outputModes":["text","voice"]}]}

使用管理员角色进行测试

curl -u admin:admin http://localhost:7860/.well-known/agent.json
{"name":"Car Booking Agent","description":"此代理提供与汽车预订相关的能力,包括预订管理和状态跟踪。","url":"http://vishal:7860","provider":{"organization":"Car Rentals Inc.","url":"https://example.com"},"version":"1.0.0","documentationUrl":"https://example.com/documentation","capabilities":{"streaming":true,"pushNotifications":true,"stateTransitionHistory":true},"authentication":{"schemes":["ApiKey"],"credentials":"Basic","valid":true,"bearerAuth":false,"basicAuth":false},"defaultInputModes":["text","voice"],"defaultOutputModes":["text","voice"],"skills":[{"id":"carBooking","name":"Car Booking Management","description":"管理汽车预订,包括创建、取消和状态检查。","tags":["booking","car","management"],"examples":["预订明天的汽车","取消我的预订","我的预订状态是什么?"],"inputModes":["text","voice"],"outputModes":["text","voice"]},{"id":"getBookingStatus","name":"Get Booking Status","description":"检查汽车预订的当前状态。","tags":["status","booking"],"examples":["我的预订状态是什么?","我的汽车准备好取了吗?"],"inputModes":["text","voice"],"outputModes":["text","voice"]},{"id":"listCarTypes","name":"List Car Types","description":"检索可用于预订的汽车类型列表。","tags":["car types","listing"],"examples":["你们有什么类型的汽车?","列出今天可用的汽车。"],"inputModes":["text","voice"],"outputModes":["text","voice"]},{"id":"getCarPricing","name":"Get Car Pricing","description":"获取不同汽车类型的定价信息。","tags":["pricing","car"],"examples":["轿车的价格是多少?","租用SUV需要多少钱?"],"inputModes":["text","voice"],"outputModes":["text","voice"]},{"id":"cancelCarBooking","name":"Cancel Car Booking","description":"取消现有的汽车预订。","tags":["cancellation","booking"],"examples":["取消我明天的预订。","我想取消我的预订。"],"inputModes":["text","voice"],"outputModes":["text","voice"]},{"id":"blockCarForMaintenance","name":"Block Car for Maintenance","description":"阻止汽车预订以进行维护。","tags":["maintenance","blocking"],"examples":["阻止汽车进行维护。","将这辆汽车暂停服务。"],"inputModes":["text","voice"],"outputModes":["text","voice"]},{"id":"generateBookingReport","name":"Generate Booking Report","description":"生成预订报告以供分析。","tags":["reporting","booking"],"examples":["生成本周所有预订的报告。","显示这个月的预订报告。"],"inputModes":["text","voice"],"outputModes":["text","voice"]}]}

从 A2A 客户端调用

curl -v -u user:password \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tasks/send",
    "params": {
      "id": "0e2fc442-180f-4cd2-b316-08b384bb236f",
      "sessionId": "fbe485db-c295-40d0-bb9c-bb16367df091",
      "message": {
        "role": "user",
        "parts": [
          {
            "type": "text",
            "text": "预订一辆马鲁蒂汽车,从托诺特到万克尔,日期为2025年5月22日",
            "metadata": null
          }
        ],
        "metadata": {
          "conversation_id": "fbe485db-c295-40d0-bb9c-bb16367df091",
          "conversation_name": "",
          "message_id": "e3749782-bc89-4691-b6cc-77239fef1ad0",
          "last_message_id": "122350f4-6ce7-436f-8ca4-0557b75b15ea"
        }
      },
      "acceptedOutputModes": ["text", "text/plain", "image/png"],
      "pushNotification": null,
      "historyLength": null,
      "metadata": {
        "conversation_id": "fbe485db-c295-10d0-bb9c-bb16367df091"
      }
    },
    "id": "d0ed3aa440f64d63a3a73d2bc7eb6358"
  }' \
  http://localhost:7860/

结果

{"jsonrpc":"2.0","id":"0e2fc442-180f-4cd2-b316-08b384bb236f","result":{"id":"0e2fc442-180f-4cd2-b316-08b384bb236f","sessionId":"fbe485db-c295-40d0-bb9c-bb16367df091","status":{"state":"submitted","message":null,"timestamp":"2025-05-23T21:07:55.790141400Z"},"history":[{"role":"user","parts":[{"type":"text","type":"text","metadata":null,"text":"预订一辆马鲁蒂汽车,从托诺特到万克尔,日期为2025年5月22日"}],"metadata":{"conversation_id":"fbe485db-c295-40d0-bb9c-bb16367df091","conversation_name":"","message_id":"e3749782-bc89-4691-b6cc-77239fef1ad0","last_message_id":"122350f4-6ce7-436f-8ca4-0557b75b15ea"}},{"role":"user","parts":[{"type":"text","type":"text","metadata":null,"text":"预订一辆马鲁蒂汽车,从托诺特到万克尔,日期为2025年5月22日"}],"metadata":{"conversation_id":"fbe485db-c295-40d0-bb9c-bb16367df091","conversation_name":"","message_id":"e3749782-bc89-4691-b6cc-77239fef1ad0","last_message_id":"122350f4-6ce7-436f-8ca4-0557b75b15ea"}}],"artifacts":null,"metadata":null,"pushNotificationConfig":null,"pushNotificationUrl":null,"subscribed":false,"subscriptionDateNow":null,"cancelled":false},"error":null}

但是,如果您使用不同的用户名和密码进行调用,将会得到访问拒绝

{"jsonrpc":"2.0","id":"0e2fc442-180f-4cd2-b316-08b384bb236f","result":{"id":"0e2fc442-180f-4cd2-b316-08b384bb236f","sessionId":"fbe485db-c295-40d0-bb9c-bb16367df091","status":{"state":"failed","message":{"role":"agent","parts":[{"type":"text","type":"text","metadata":{},"text":"处理失败:访问被拒绝"}],"metadata":null},"timestamp":"2025-05-23T21:27:06.172634900Z"},"history":[{"role":"user","parts":[{"type":"text","type":"text","metadata":null,"text":"预订一辆马鲁蒂汽车,从托诺特到万克尔,日期为2025年5月22日"}],"metadata":{"conversation_id":"fbe485db-c295-40d0-bb9c-bb16367df091","conversation_name":"","message_id":"e3749782-bc89-4691-b6cc-77239fef1ad0","last_message_id":"122350f4-6ce7-436f-8ca4-0557b75b15ea"}},{"role":"user","parts":[{"type":"text","type":"text","metadata":null,"text":"预订一辆马鲁蒂汽车,从托诺特到万克尔,日期为2025年5月22日"}],"metadata":{"conversation_id":"fbe485db-c295-40d0-bb9c-bb16367df091","conversation_name":"","message_id":"e3749782-bc89-4691-b6cc-77239fef1ad0","last_message_id":"122350f4-6ce7-436f-8ca4-0557b75b15ea"}}],"artifacts":null,"metadata":null,"pushNotificationConfig":null,"pushNotificationUrl":null,"subscribed":false,"subscriptionDateNow":null,"cancelled":false},"error":null}

测试 MCP 客户端

不使用角色进行测试

curl -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"tools/list","params":{},"id":9}' http://localhost:7860/
{"result":{"_meta":{},"tools":[{"parameters":null,"inputSchema":{"type":"object","properties":{"provideAllValuesInPlainEnglish":{"type":"string","description":"{\n    \"arg0\": \"\"\n}","additionalProperties":{},"items":false}},"required":["provideAllValuesInPlainEnglish"]},"annotations":null,"description":"获取汽车预订状态","name":"getBookingStatus","type":null},{"parameters":null,"inputSchema":{"type":"object","properties":{"provideAllValuesInPlainEnglish":{"type":"string","description":"{\n    \"methodName\": \"listCarTypes\",\n    \"parameters\": []\n}","additionalProperties":{},"items":false}},"required":["provideAllValuesInPlainEnglish"]},"annotations":null,"description":"查看可用汽车类型","name":"listCarTypes","type":null},{"parameters":null,"inputSchema":{"type":"object","properties":{"provideAllValuesInPlainEnglish":{"type":"string","description":"{\n    \"arg0\": \"\"\n}","additionalProperties":{},"items":false}},"required":["provideAllValuesInPlainEnglish"]},"annotations":null,"description":"获取汽车类型的定价","name":"getCarPricing","type":null}]},"id":9,"jsonrpc":"2.0"}

使用用户角色进行测试

curl -u user:password -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"tools/list","params":{},"id":9}' http://localhost:7860/

您将获得

{"result":{"_meta":{},"tools":[{"parameters":null,"inputSchema":{"type":"object","properties":{"provideAllValuesInPlainEnglish":{"type":"string","description":"{\n    \"parameters\": {\n        \"arg0\": {\n            \"type\": \"String\",\n            \"fieldValue\": \"\"\n        },\n        \"arg1\": {\n            \"type\": \"String\",\n            \"fieldValue\": \"\"\n        },\n        \"arg2\": {\n            \"type\": \"String\",\n            \"fieldValue\": \"\"\n        }\n    }\n}","additionalProperties":{},"items":false}},"required":["provideAllValuesInPlainEnglish"]},"annotations":null,"description":"根据给定详情预订汽车","name":"bookCar","type":null},{"parameters":null,"inputSchema":{"type":"object","properties":{"provideAllValuesInPlainEnglish":{"type":"string","description":"{\n    \"arg0\": \"\"\n}","additionalProperties":{},"items":false}},"required":["provideAllValuesInPlainEnglish"]},"annotations":null,"description":"获取汽车预订状态","name":"getBookingStatus","type":null},{"parameters":null,"inputSchema":{"type":"object","properties":{"provideAllValuesInPlainEnglish":{"type":"string","description":"{\n    \"parameters\": []\n}","additionalProperties":{},"items":false}},"required":["provideAllValuesInPlainEnglish"]