spring-boot - 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 配置的更改。我没有使用它们中的任何一个,我完全在本地运行它。我不确定我在这里缺少什么。我这里有代码。任何帮助表示赞赏。
解决方案
推荐阅读
- php - 在前缀根路径中找不到路由
- kotlin - 在 Kotlin 中覆盖 Java final 函数的 Kotlin 编译器问题
- python - 从包含数组的不同列之间的匹配元素创建一个新列
- pyspark - 如何在 `groupBy()` 之后选择 DataFrame 的特定行?
- python - 注释不存在的 dict 字段不应该产生错误吗?
- c# - 在 WPF 应用程序中包含字体
- ios - UINavigationBar(嵌入在 UIImagePickerController 中)背景颜色未更新仅在 iOS13 中发生的此问题
- android - kotlin 是否有用于从两种不同类型的列表中获取公共数据的高阶函数?
- javascript - 如何在axios中添加拦截器功能?
- ios - 当我从 Scheme Url(Swift 项目)启动应用程序时未调用 openURL