Spring 安全密钥斗篷适配器在浏览器中的另一个选项卡注销时无法处理单点注销



我已经实现了一个使用spring安全和Keycloak的spring启动Web应用程序,以根据本教程对用户进行身份验证。我使用了maven,Spring boot 2.2.2和Keycloak 8.0.1。除单点注销中的问题外,所有操作都正常工作。当我在浏览器(http://localhost:8080/books(的选项卡中打开spring启动应用程序的安全路径时,在另一个选项卡中打开Keycloak帐户页面(http://localhost:8180/auth/realms/{realm_name}/帐户(并使用其中一个用户登录,另一个选项卡将知道登录,并在重新加载页面后,该页面也将进行身份验证。但问题是,当两个选项卡都登录并首先从帐户页面注销并重新加载 Spring 启动应用程序时,用户保持活动状态,并且应用程序不知道其他选项卡中的注销操作。我该如何处理这个问题?

我的项目资源树如下图所示: 项目资源树

这是我的绒球.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.sso</groupId>
<artifactId>demoapp</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demoapp</name>
<description>Demo project for Spring Boot</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>13</java.version>
<keycloak.version>8.0.1</keycloak.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- Keycloak Adapter -->
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-test-helper</artifactId>
<version>${keycloak.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.keycloak.bom</groupId>
<artifactId>keycloak-adapter-bom</artifactId>
<version>${keycloak.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

这是安全配置.java

@KeycloakConfiguration
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
SimpleAuthorityMapper grantedAuthorityMapper = new SimpleAuthorityMapper();
grantedAuthorityMapper.setPrefix("ROLE_");
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(grantedAuthorityMapper);
auth.authenticationProvider(keycloakAuthenticationProvider);
}
/**
* Defines the session authentication strategy.
*/
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
/**
* Define an HttpSessionManager bean only if missing.
*/
@Bean
@Override
@ConditionalOnMissingBean(HttpSessionManager.class)
protected HttpSessionManager httpSessionManager() {
return new HttpSessionManager();
}
/**
* Define security constraints for the application resources.
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
.authorizeRequests()
.antMatchers("/books").authenticated()
.antMatchers("/manager").hasRole("admin")
.anyRequest().permitAll();
}
@Bean
public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher() {
return new ServletListenerRegistrationBean<HttpSessionEventPublisher>(new HttpSessionEventPublisher());
}
}

这是库控制器.java

@Controller
public class LibraryController {
private final HttpServletRequest request;
private final BookRepository bookRepository;
@Autowired
public LibraryController(HttpServletRequest request, BookRepository bookRepository) {
this.request = request;
this.bookRepository = bookRepository;
}
@GetMapping(value = "/")
public String getHome() {
return "index";
}
@GetMapping(value = "/books")
public String getBooks(Model model) {
configCommonAttributes(model);
model.addAttribute("books", bookRepository.readAll());
return "books";
}
@GetMapping(value = "/manager")
public String getManager(Model model) {
configCommonAttributes(model);
model.addAttribute("books", bookRepository.readAll());
return "manager";
}
@GetMapping(value = "/logout")
public String logout() throws ServletException {
request.logout();
return "redirect:/";
}
private void configCommonAttributes(Model model) {
model.addAttribute("firstname", getKeycloakSecurityContext().getIdToken().getGivenName());
model.addAttribute("lastname", getKeycloakSecurityContext().getIdToken().getFamilyName());
model.addAttribute("email", getKeycloakSecurityContext().getIdToken().getEmail());
}
/**
* The KeycloakSecurityContext provides access to several pieces of information
* contained in the security token, such as user profile information.
*/
private KeycloakSecurityContext getKeycloakSecurityContext() {
return (KeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName());
}
}

下面是我的演示应用程序.java

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoappApplication {
public static void main(String[] args) {
SpringApplication.run(DemoappApplication.class, args);
}
}

通过在 Keycloak 服务器(管理控制台(的相应客户端配置页面中将我的 spring 启动应用程序的基本 URL 设置为Admin-URL,解决了这个问题。现在,Spring 启动应用程序知道用户从其他应用程序注销。

相关内容

  • 没有找到相关文章

最新更新