首页 > 解决方案 > Keycloak + Spring Boot + Swagger 2

问题描述

我正在尝试在用户访问 swagger-ui 之前对其进行身份验证。我正在使用 Keycloak 进行 ID 管理。我正在按照此处给出的示例进行操作。

以下是我的安全配置

@Configuration
@EnableWebSecurity
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        KeycloakAuthenticationProvider keycloakAuthenticationProvider = new KeycloakAuthenticationProvider();
        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
        authenticationManagerBuilder.authenticationProvider(keycloakAuthenticationProvider);
    }

    @Bean
    public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
        return new KeycloakSpringBootConfigResolver();
    }

    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        http.csrf().disable();
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .exceptionHandling().accessDeniedHandler(
                (request, response, accessDeniedException) -> response.setStatus(HttpServletResponse.SC_NOT_FOUND)
        )
                .and()
                .anonymous()
                .and()
                .authorizeRequests().anyRequest().authenticated()
                .and()
                .httpBasic().disable()
                .formLogin().disable()
                .logout().disable();
    }


}

下面是我的招摇配置

@Configuration
@Slf4j
public class SwaggerConfig {

    @Value("${keycloak.auth-server-url}")
    private String AUTH_SERVER;

    @Value("${keycloak.credentials.secret}")
    private String CLIENT_SECRET;

    @Value("${keycloak.resource}")
    private String CLIENT_ID;

    @Value("${keycloak.realm}")
    private String REALM;

    private static final String OAUTH_NAME = "spring_oauth";
    private static final String ALLOWED_PATHS = "src/main/java/io/chait/swagger/demo/.*";
    private static final String GROUP_NAME = "swagger-demo";
    private static final String TITLE = "API Documentation for swagger-demo Application";
    private static final String DESCRIPTION = "Description here";
    private static final String VERSION = "1.0";

    @Bean
    public Docket taskApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName(GROUP_NAME)
                .useDefaultResponseMessages(true)
                .apiInfo(apiInfo())
                .select()
                .paths(regex(ALLOWED_PATHS))
                .build()
                .securitySchemes(Arrays.asList(securityScheme()))
                .securityContexts(Arrays.asList(securityContext()));
    }

    private ApiInfo apiInfo() {
        return new
                ApiInfoBuilder().title(TITLE).description(DESCRIPTION).version(VERSION).build();
    }

    @Bean
    public SecurityConfiguration security() {
        return SecurityConfigurationBuilder.builder()
                .realm(REALM)
                .clientId(CLIENT_ID)
                .clientSecret(CLIENT_SECRET)
                .appName(GROUP_NAME)
                .scopeSeparator(" ")
                .build();
    }

    private SecurityScheme securityScheme() {
        GrantType grantType =
                new AuthorizationCodeGrantBuilder()
                        .tokenEndpoint(new TokenEndpoint(AUTH_SERVER + "/realms/" + REALM + "/protocol/openid-connect/token", GROUP_NAME))
                        .tokenRequestEndpoint(
                                new TokenRequestEndpoint(AUTH_SERVER + "/realms/" + REALM + "/protocol/openid-connect/auth", CLIENT_ID, CLIENT_SECRET))
                        .build();

        SecurityScheme oauth =
                new OAuthBuilder()
                        .name(OAUTH_NAME)
                        .grantTypes(Arrays.asList(grantType))
                        .scopes(Arrays.asList(scopes()))
                        .build();
        return oauth;
    }

    private AuthorizationScope[] scopes() {
        AuthorizationScope[] scopes = {
                new AuthorizationScope("user", "for CRUD operations"),
                new AuthorizationScope("read", "for read operations"),
                new AuthorizationScope("write", "for write operations")
        };
        return scopes;
    }

    private SecurityContext securityContext() {
        return SecurityContext.builder()
                .securityReferences(Arrays.asList(new SecurityReference(OAUTH_NAME, scopes())))
                .forPaths(PathSelectors.regex(ALLOWED_PATHS))
                .build();
    }

}

下面是我的属性文件

spring.datasource.url=jdbc:postgresql://localhost:5432/personal
spring.datasource.password=postgres
spring.datasource.username=postgres
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=update


# keycloak config

keycloak.auth-server-url=http://localhost:8180/auth
keycloak.realm=local
keycloak.resource=swagger-demo
keycloak.public-client=true
keycloak.credentials.secret=fb652c4a-70cb-4b81-a339-fa87054f77a0

spring.application.name=swagger-demo

下面是我的引导类

@SpringBootApplication
@EnableJpaRepositories
@EnableSwagger2
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

当我启动应用程序并访问http://localhost:8080/swagger-demo/swagger-ui/应用程序时,我会将我重定向到 Keycloak,我在其中输入用户凭据。身份验证后,我得到以下异常

2021-04-02 21:46:04.163 ERROR 4208 --- [nio-8080-exec-8] o.k.adapters.OAuthRequestAuthenticator   : failed to turn code into token
2021-04-02 21:46:04.164 ERROR 4208 --- [nio-8080-exec-8] o.k.adapters.OAuthRequestAuthenticator   : status from server: 401
2021-04-02 21:46:04.164 ERROR 4208 --- [nio-8080-exec-8] o.k.adapters.OAuthRequestAuthenticator   :    {"error":"unauthorized_client","error_description":"Client secret not provided in request"}

有关此异常的所有相关线程都指向 nginx 配置或 Docker 配置的更改。我没有使用它们中的任何一个,我完全在本地运行它。我不确定我在这里缺少什么。我这里有代码。任何帮助表示赞赏。

标签: spring-bootspring-securityswaggerkeycloakswagger-ui

解决方案


推荐阅读