You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Security 6整合Discord作为OAuth2身份提供商遇故障求助

Spring Security 6 整合 Discord OAuth2 完整配置方案

1. 修复 Token 端点 HTTP 400 问题

Discord 的 OAuth2 Token 端点强制要求通过Basic Auth传递客户端ID和密钥,Spring Security 6 默认不会自动适配这个规则,只需在配置里显式指定认证方式即可,无需自定义拦截器:

application.yaml 核心配置

spring:
  security:
    oauth2:
      client:
        registration:
          discord:
            client-id: 你的Discord客户端ID
            client-secret: 你的Discord客户端密钥
            client-authentication-method: client_secret_basic
            authorization-grant-type: authorization_code
            redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
            scope: identify, email
        provider:
          discord:
            authorization-uri: https://discord.com/api/oauth2/authorize
            token-uri: https://discord.com/api/oauth2/token
            user-info-uri: https://discord.com/api/users/@me
            user-name-attribute: id

关键配置是client-authentication-method: client_secret_basic,Spring Security 会自动生成 Basic Auth 头并传递到 Token 端点。

2. 修复 JSON 解析失败问题

Discord 返回的 Token 响应采用蛇形命名(如access_token、refresh_token),Spring Security 默认转换器未适配该格式,导致解析为空。需自定义响应转换器:

自定义 Token 响应转换器配置类

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.endpoint.DefaultAuthorizationCodeTokenResponseClient;
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;

@Configuration
public class DiscordOAuth2Config {

    @Bean
    public OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> authorizationCodeTokenResponseClient() {
        DefaultAuthorizationCodeTokenResponseClient tokenResponseClient = new DefaultAuthorizationCodeTokenResponseClient();
        
        OAuth2AccessTokenResponseHttpMessageConverter converter = new OAuth2AccessTokenResponseHttpMessageConverter();
        ObjectMapper objectMapper = new ObjectMapper();
        // 强制使用蛇形命名解析响应JSON
        objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
        converter.setObjectMapper(objectMapper);
        
        tokenResponseClient.setAccessTokenResponseConverter(converter);
        return tokenResponseClient;
    }
}

3. Vaadin 适配配置

需确保 OAuth2 登录回调路径不被 Vaadin 路由拦截,同时在 Spring Security 中放行相关路径:

Spring Security 过滤链配置

import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;

@EnableWebSecurity
public class SecurityConfig {

    private final OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> tokenResponseClient;

    public SecurityConfig(OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> tokenResponseClient) {
        this.tokenResponseClient = tokenResponseClient;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/login/**", "/oauth2/**").permitAll()
                .anyRequest().authenticated()
            )
            .oauth2Login(oauth2 -> oauth2
                .tokenEndpoint(token -> token
                    .accessTokenResponseClient(tokenResponseClient)
                )
            );
        return http.build();
    }
}

验证示例

在 Vaadin 视图中获取 Discord 用户信息:

import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.user.OAuth2User;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Route;

@Route("")
public class MainView extends VerticalLayout {
    public MainView(@AuthenticationPrincipal OAuth2User oauth2User) {
        add("Discord用户ID: " + oauth2User.getAttribute("id"));
        add("Discord用户名: " + oauth2User.getAttribute("username"));
        add("邮箱: " + oauth2User.getAttribute("email"));
    }
}

内容的提问来源于stack exchange,提问作者klenkes74

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 06:53:13