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

如何配置Spring Boot+Keycloak实现Swagger UI账号密码登录

问题描述

我希望通过Swagger UI结合Keycloak与Spring Boot Security实现账号密码登录。目前已能通过Postman使用生成的Bearer Token完成接口调用,但不清楚如何配置Swagger UI支持用户直接输入账号密码登录的方式。


现有配置代码

Security配置:

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
@RequiredArgsConstructor
public class SecurityConfig {
    private static final String[] AUTH_WHITELIST = {"/swagger-resources", "/swagger-resources/**", "/configuration/ui",
            "/configuration/security", "/swagger-ui.html", "/webjars/**", "/v3/api-docs/**", "v3/api-docs",
            "/api/public/**", "/api/public/authenticate", "/actuator/*", "/swagger-ui/**", "/api-docs/**"};

    private final JwtAuthConverter jwtAuthConverter;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.csrf(csrf -> csrf.disable());
        http.authorizeHttpRequests(auth -> auth.requestMatchers(AUTH_WHITELIST).permitAll().anyRequest().authenticated());
        http.oauth2ResourceServer(o2 -> o2.jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthConverter)));
        http.sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
        return http.build();
    }
}

JwtAuthConverter转换器:

@Component
public class JwtAuthConverter implements Converter<Jwt, AbstractAuthenticationToken> {

    private final JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();

    @Value("${jwt.auth.converter.principle_attribute}")
    private String principleAttribute;
    @Value("${jwt.auth.converter.resource-id}")
    private String resourceId;

    @Override
    public AbstractAuthenticationToken convert(@NonNull Jwt jwt) {
        Collection<GrantedAuthority> authorities = Stream.concat(jwtGrantedAuthoritiesConverter.convert(jwt).stream(), extractResourceRoles(jwt).stream()).collect(Collectors.toSet());
        return new JwtAuthenticationToken(jwt, authorities, getPrincipleClaimName(jwt));
    }

    private String getPrincipleClaimName(Jwt jwt) {
        String claimName = JwtClaimNames.SUB;
        if (principleAttribute != null) {
            claimName = principleAttribute;
        }
        return jwt.getClaim(claimName);
    }

    private Collection<? extends GrantedAuthority> extractResourceRoles(Jwt jwt) {
        Map<String, Object> resourceAccess;
        Map<String, Object> resource;
        Collection<String> resourceRoles;
        if (jwt.getClaim("resource_access") == null) {
            return Set.of();
        }
        resourceAccess = jwt.getClaim("resource_access");

        if (resourceAccess.get(resourceId) == null) {
            return Set.of();
        }
        resource = (Map<String, Object>) resourceAccess.get(resourceId);

        resourceRoles = (Collection<String>) resource.get("roles");
        return resourceRoles.stream().map(role -> new SimpleGrantedAuthority("ROLE_" + role)).collect(Collectors.toSet());
    }
}

Swagger配置:

@Configuration
public class SwaggerConfig {
    private static final String OAUTH_SCHEME_BEARER = "bearerAuth";

    @Bean
    public OpenAPI customizeOpenAPI() {
        return new OpenAPI()
                .addSecurityItem(new SecurityRequirement()
                        .addList(OAUTH_SCHEME_BEARER))
                .components(new Components()
                        .addSecuritySchemes(OAUTH_SCHEME_BEARER, new SecurityScheme()
                                .name(OAUTH_SCHEME_BEARER)
                                .type(SecurityScheme.Type.HTTP)
                                .scheme("bearer")
                                .bearerFormat("JWT")));
    }

}

配置解决方案

1. 修改Swagger配置,支持OAuth2 Password Flow

替换原Swagger配置,添加OAuth2密码模式支持,让Swagger UI可以直接调用Keycloak令牌接口获取Bearer Token:

@Configuration
public class SwaggerConfig {
    private static final String OAUTH_SCHEME_OAUTH2 = "oauth2";

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

    @Bean
    public OpenAPI customizeOpenAPI() {
        // 构建OAuth2密码流配置
        OAuthFlow oAuthFlow = new OAuthFlow()
                .tokenUrl(issuerUri + "/protocol/openid-connect/token")
                .scopes(new Scopes().addString("openid", "OpenID Connect scope")); // 可根据需求添加其他scope

        SecurityScheme securityScheme = new SecurityScheme()
                .name(OAUTH_SCHEME_OAUTH2)
                .type(SecurityScheme.Type.OAUTH2)
                .flows(new OAuthFlows().password(oAuthFlow));

        return new OpenAPI()
                .addSecurityItem(new SecurityRequirement().addList(OAUTH_SCHEME_OAUTH2))
                .components(new Components().addSecuritySchemes(OAUTH_SCHEME_OAUTH2, securityScheme));
    }
}

2. 配置Swagger UI的OAuth客户端参数

在application.yml或application.properties中添加以下配置:

springdoc:
  swagger-ui:
    oauth:
      client-id: your-keycloak-client-id  # 替换为你的Keycloak客户端ID
      client-secret: your-keycloak-client-secret  # 替换为Keycloak客户端密钥(保密类型客户端需配置)
      use-pkce-with-authorization-code-grant: false  # 密码流无需PKCE

3. 调整Keycloak客户端配置

在Keycloak控制台中找到目标客户端,完成以下配置:

  • 开启Direct Access Grants Enabled(允许密码模式)
  • 根据需求设置Access Type为confidential或public
  • 确保有效重定向URI包含Swagger UI地址,例如http://localhost:8080/swagger-ui/**

4. 验证Security配置

现有AUTH_WHITELIST已覆盖Swagger相关路径,无需额外修改。

完成上述配置后,启动应用访问Swagger UI(默认地址http://localhost:8080/swagger-ui.html),点击右上角Authorize按钮,输入Keycloak用户名、密码及客户端信息,即可自动获取令牌并携带到接口请求中。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 18:35:20