SpringAI MCP添加OAuth2鉴权

前言

现Spring AI MCP需要支持授权能力,官方在2025-03-26提供了OAuth2协议的授权支持,具体参考文档。由于spring完善的生态,可以使用oauth2-resource-server和oauth2-authorization-server组件提供mcp server的oauth2的鉴权流程。官方提供了一个简单的例子。
官方博客https://spring.io/blog/2025/04/02/mcp-server-oauth2
官方例子https://github.com/spring-projects/spring-ai-examples/blob/main/model-context-protocol/weather/starter-webmvc-oauth2-server
需要注意:当前只支持spring-ai-mcp-server-webmvc-spring-boot-starter暂时不支持spring-ai-mcp-server-webflux-spring-boot-starter!!!

OAuth2.0授权流程

由于官方提供的例子是MCP Server本来就是Oauth的授权方,下图直接使用MCP官方文档中的2.5章节的图。

企业微信截图_17537018732304.png

Demo测试

1,添加依赖

# spring boot版本要3.4.5以上
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.4.5</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
 
# mcp server依赖,当前只能支持webmvc,webflux不起效果。
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>
 
# oauth2依赖
<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>

2,添加配置文件

# 不走浏览器的鉴权流程。直接使用硬编码。正常的流程需要走浏览器登录获得。
# client-id和client-secret这里使用硬编码
spring.security.oauth2.authorizationserver.client.oidc-client.registration.client-id=xxx
spring.security.oauth2.authorizationserver.client.oidc-client.registration.client-secret={noop}xxx
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
#spring.security.oauth2.authorizationserver.endpoint.token-uri=/mcp/oauth2/token

3,编写代码
创建一个SecurityConfiguration安全配置类。

import static org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer.authorizationServer;
 
@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
         
    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
                .with(authorizationServer(), Customizer.withDefaults())
                //--启用 Spring 授权服务器和 Spring 资源服务器。
                .oauth2ResourceServer(resource -> resource.jwt(Customizer.withDefaults()))
                .csrf(CsrfConfigurer::disable)//--关闭 CSRF(跨站请求伪造)。MCP 服务器并非为基于浏览器的交互而设计,因此不需要 CSRF。
                .cors(Customizer.withDefaults())//--开启 CORS(跨域资源共享)支持,以便我们可以使用 MCP 检查器对服务器进行演示。
                .build();
    }
 
    @Value("${spring.security.oauth2.authorizationserver.client.oidc-client.registration.client-id}")
    private String clientId;
 
    @Value("${spring.security.oauth2.authorizationserver.client.oidc-client.registration.client-secret}")
    private String clientSecret;
 
    @Bean
    public RegisteredClientRepository registeredClientRepository() {
        //--OAuth2客户端
        RegisteredClient mcpClient = RegisteredClient.withId(UUID.randomUUID().toString())
                .clientId(clientId) //--硬编码的clientId
                .clientSecret(clientSecret)//--硬编码的clientSecret
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
                .tokenSettings(TokenSettings.builder()
                        .accessTokenTimeToLive(Duration.ofHours(1))//--token过期时间
                        .build())
                .clientSettings(ClientSettings.builder()
                        .requireAuthorizationConsent(false)
                        .build())
                .scope("LIST")
                .build();
       //--这里使用InMemoryRegisteredClientRepository,如果是正式环境,建议写到redis或者mysql中。
        return new InMemoryRegisteredClientRepository(mcpClient);
    }
 
}

4,测试
启动MCP Server服务。
a)获得Token

curl --location 'http://localhost:8115/oauth2/token' \
--data-urlencode 'grant_type=client_credentials'
image.png

b)请求MCP Server

curl --location 'http://localhost:8115/sse' \
--header 'Authorization: Bearer  <ACCESS_TOKEN>'

使用错误的token或无token的情况下会报401无权错误。

企业微信截图_17537028693678.png
企业微信截图_17537023094772.png

使用上文中获得的正确的token。

企业微信截图_17537028006708.png
企业微信截图_17537024112539.png

可以看到,在添加oauth2.0的鉴权后,mcp client必须要先通过授权接口获得token才能请求mcp server,否则会出现401的无权错误。

总结

1,官方提供的博客和例子能mcp server使用oauth2.0协议授权,验证只支持webmvc,不支持webflux。
2,mcp server添加oauth2.0协议后,需要客户端先通过/oauth2/token接口获得token,然后在请求mcp server的所有接口。
3,当前spring ai mcp只支持服务端接入oauth2.0,而spring ai client由于mcp javasdk不支持,要么改源码,要么就需要等官方的版本。
4,官方demo使用InMemoryRegisteredClientRepository,生产需要自己写到redis或者mysql中。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容