Spring Boot Keycloak 适配器无法授权对上下文的请求 url“/”
Spring Boot Keycloak Adapter cannot authorize requests to context url "/"
我有一个简单的 Spring Boot (2.4.5-SNAPSHOT) Web 项目,使用 keycloak-spring-boot-starter
(12.0.4) 适配器进行 Keycloak 集成。除了应用程序的 context/base url 之外,我可以保护所有端点。到达此基地 url 的请求未经过身份验证。 configure
方法有误吗?
http://localhost:3000/greetings
是安全的,重定向到 Keycloak 登录。但是 http://localhost:3000
是不安全的。
HelloController.java
@RestController
public class HelloController {
@GetMapping("/greetings")
public ResponseEntity<String> getGreetings() {
return ResponseEntity.ok("Hello world!");
}
@GetMapping("/")
public ResponseEntity<String> getContextGreetings() {
return ResponseEntity.ok("Hello world context!");
}
}
KeycloakSecurityConfig.java
@Configuration
@EnableWebSecurity
public class KeycloakSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.csrf().disable()
.authorizeRequests().antMatchers("/**").authenticated();
//.authorizeRequests(authorize -> authorize.anyRequest().authenticated());
// Also tried the commented one, doesn't work either.
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
@Bean
public KeycloakConfigResolver keycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
}
application.properties
server.port=3000
keycloak.realm=myrealm
keycloak.auth-server-url=http://localhost:8080/auth
keycloak.ssl-required=external
keycloak.resource=my-client
keycloak.credentials.secret=b5c3154c-012b-4ce2-af14-d58505a2a54d
keycloak.use-resource-role-mappings=true
build.gradle
...
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
implementation 'org.keycloak:keycloak-spring-boot-starter:12.0.4'
implementation 'org.keycloak.bom:keycloak-adapter-bom:12.0.4'
implementation 'com.fasterxml.jackson.core:jackson-core:2.12.2'
}
找到原因感谢以下.
在configure
方法中,super.configure(http);
被调用。父 configure
方法使注销 url 不安全,这是有道理的,因为它是注销后的重定向页面。为了克服这个问题,需要将 logoutSuccessUrl
设置为另一个 url.
参见KeycloakWebSecurityConfigurerAdapter
方法的最后一行:
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().requireCsrfProtectionMatcher(keycloakCsrfRequestMatcher())
.and()
.sessionManagement()
.sessionAuthenticationStrategy(sessionAuthenticationStrategy())
.and()
.addFilterBefore(keycloakPreAuthActionsFilter(), LogoutFilter.class)
.addFilterBefore(keycloakAuthenticationProcessingFilter(), LogoutFilter.class)
.addFilterAfter(keycloakSecurityContextRequestFilter(), SecurityContextHolderAwareRequestFilter.class)
.addFilterAfter(keycloakAuthenticatedActionsRequestFilter(), KeycloakSecurityContextRequestFilter.class)
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint())
.and()
.logout()
.addLogoutHandler(keycloakLogoutHandler())
.logoutUrl("/sso/logout").permitAll()
.logoutSuccessUrl("/"); //permits the path
}
我有一个简单的 Spring Boot (2.4.5-SNAPSHOT) Web 项目,使用 keycloak-spring-boot-starter
(12.0.4) 适配器进行 Keycloak 集成。除了应用程序的 context/base url 之外,我可以保护所有端点。到达此基地 url 的请求未经过身份验证。 configure
方法有误吗?
http://localhost:3000/greetings
是安全的,重定向到 Keycloak 登录。但是 http://localhost:3000
是不安全的。
HelloController.java
@RestController
public class HelloController {
@GetMapping("/greetings")
public ResponseEntity<String> getGreetings() {
return ResponseEntity.ok("Hello world!");
}
@GetMapping("/")
public ResponseEntity<String> getContextGreetings() {
return ResponseEntity.ok("Hello world context!");
}
}
KeycloakSecurityConfig.java
@Configuration
@EnableWebSecurity
public class KeycloakSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.csrf().disable()
.authorizeRequests().antMatchers("/**").authenticated();
//.authorizeRequests(authorize -> authorize.anyRequest().authenticated());
// Also tried the commented one, doesn't work either.
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
@Bean
public KeycloakConfigResolver keycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
}
application.properties
server.port=3000
keycloak.realm=myrealm
keycloak.auth-server-url=http://localhost:8080/auth
keycloak.ssl-required=external
keycloak.resource=my-client
keycloak.credentials.secret=b5c3154c-012b-4ce2-af14-d58505a2a54d
keycloak.use-resource-role-mappings=true
build.gradle
...
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
implementation 'org.keycloak:keycloak-spring-boot-starter:12.0.4'
implementation 'org.keycloak.bom:keycloak-adapter-bom:12.0.4'
implementation 'com.fasterxml.jackson.core:jackson-core:2.12.2'
}
找到原因感谢以下
在configure
方法中,super.configure(http);
被调用。父 configure
方法使注销 url 不安全,这是有道理的,因为它是注销后的重定向页面。为了克服这个问题,需要将 logoutSuccessUrl
设置为另一个 url.
参见KeycloakWebSecurityConfigurerAdapter
方法的最后一行:
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().requireCsrfProtectionMatcher(keycloakCsrfRequestMatcher())
.and()
.sessionManagement()
.sessionAuthenticationStrategy(sessionAuthenticationStrategy())
.and()
.addFilterBefore(keycloakPreAuthActionsFilter(), LogoutFilter.class)
.addFilterBefore(keycloakAuthenticationProcessingFilter(), LogoutFilter.class)
.addFilterAfter(keycloakSecurityContextRequestFilter(), SecurityContextHolderAwareRequestFilter.class)
.addFilterAfter(keycloakAuthenticatedActionsRequestFilter(), KeycloakSecurityContextRequestFilter.class)
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint())
.and()
.logout()
.addLogoutHandler(keycloakLogoutHandler())
.logoutUrl("/sso/logout").permitAll()
.logoutSuccessUrl("/"); //permits the path
}