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

Spring Boot集成Azure B2C与Swagger认证问题排查

问题:Swagger UI 对接 Azure AD B2C 认证报错

问题现象

  1. 初始报错:使用Swagger UI通过Azure B2C进行认证时,提示缺少code_challenge参数,但无法在Azure或Swagger配置中手动添加该参数。
  2. 后续报错:参考Azure文档尝试添加code_challenge后,出现新错误:AADB2C90184:提供的code_challenge_method不被支持,支持的值为plain或S256。

Swagger 配置代码

@Bean
public OpenAPI openApi() {
    return new OpenAPI()
        .info(new Info()
            .title("API")
            .version("1.0.0"))
        .addServersItem(new Server().url("http://localhost:8080"))
        .components(new Components()
            .addSecuritySchemes("oauth2", new SecurityScheme()
                    .type(OAUTH2)
                    .description("Sign in with Azure AD B2C OAuth2")
                    .flows(new OAuthFlows()
                        .authorizationCode(new OAuthFlow()
                            .authorizationUrl("https://costcoapp.b2clogin.com/costcoapp.onmicrosoft.com/B2C_1_signupsignin1/oauth2/v2.0/authorize")
                            .tokenUrl("https://costcoapp.b2clogin.com/costcoapp.onmicrosoft.com/B2C_1_signupsignin1/oauth2/v2.0/token")
                            .scopes(new Scopes()
                                .addString("https://costcoapp.onmicrosoft.com/f342g5-5a6b-4341-a4fc-3674gr52779/read", "Read access to demo API")
                                
                            )
                        )
                    )
            )
            .addSecuritySchemes("bearerToken",
                new SecurityScheme()
                    .type(HTTP)
                    .description("Use Access Token obtained from Azure AD B2C OAuth2")
                    .scheme("bearer")
                    .bearerFormat("JWT")
            )
        );
}

Security 配置代码

@Configuration
@EnableMethodSecurity
@RequiredArgsConstructor
public class SecurityConfiguration {

    private final AadB2cOidcLoginConfigurer configurer;

    private final JwtClaimResolver jwtClaimResolver;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeRequests(config -> config
                .requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll()
                .anyRequest().authenticated())
            .oauth2ResourceServer(config -> config
                .jwt()
                .jwtAuthenticationConverter(jwtAuthenticationConverter()))
            .formLogin(AbstractHttpConfigurer::disable)
            .logout(AbstractHttpConfigurer::disable)
            .csrf(AbstractHttpConfigurer::disable)
            .httpBasic(AbstractHttpConfigurer::disable);
        http.sessionManagement($ -> $.sessionCreationPolicy(STATELESS));
        http.apply(configurer);
        return http.build();
    }

    private JwtAuthenticationConverter jwtAuthenticationConverter() {
        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwt -> jwtClaimResolver.getUserGroups(jwt)
            .stream()
            .map(this::mapToGrantedAuthority)
            .toList());
        return jwtAuthenticationConverter;
    }

    private GrantedAuthority mapToGrantedAuthority(String userGroup) {
        return new SimpleGrantedAuthority("ROLE_" + userGroup);
    }

}

application.yaml 配置代码

spring:
  cloud:
    azure:
      active-directory:
        b2c:
          enabled: true
          profile:
            tenant-id: <my-tenant-id>
          credential:
            client-id: <my-client-id>
            client-secret: <my-secret>
          base-uri: https://costcoapp.b2clogin.com/costcoapp.onmicrosoft.com
          user-flows:
            sign-up-or-sign-in: B2C_1_signupsignin1

springdoc:
  api-docs:
    enabled: true
  swagger-ui:
    oauth:
      client-id: <my-client-id>
      client-secret: <my-secret>
    oauth2-redirect-url: http://localhost:8080/swagger-ui/oauth2-redirect.html

更新:尝试添加 code_challenge 的代码

@SneakyThrows
private String generateChallenge() {
    SecureRandom secureRandom = new SecureRandom();
    int cvLength = secureRandom.nextInt(85) + 43;
    String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
    StringBuilder codeVerifier = new StringBuilder(cvLength);
    for (int i = 0; i < cvLength; i++) {
        codeVerifier.append(chars.charAt(secureRandom.nextInt(chars.length())));
    }

    MessageDigest digest = MessageDigest.getInstance("SHA-256");
    byte[] encodedHash = digest.digest(codeVerifier.toString().getBytes(java.nio.charset.StandardCharsets.UTF_8));

    return Base64.getUrlEncoder().withoutPadding().encodeToString(encodedHash);
}

@SneakyThrows
private URL buildAuthUrl() {
    String challenge = generateChallenge();
    String baseUrl = "https://costcoapp.b2clogin.com/costcoapp.onmicrosoft.com/b2c_1_signupsignin1/oauth2/v2.0/authorize";

    UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(baseUrl)
        .queryParam("client_id", "f342g5-5a6b-4341-a4fc-3674gr52779")
        .queryParam("response_type", "code")
        .queryParam("redirect_uri", "http://localhost:8080/swagger-ui/oauth2-redirect.html")
        .queryParam("response_mode", "query")
        .queryParam("scope", "openid")
        .queryParam("code_challenge", challenge)
        .queryParam("code_challenge_method", "plain");

    return  uriBuilder.build().toUri().toURL();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 00:14:52