Springboot继承Keycloak实现单点登陆与退出

由于网上博客大部分都只有登陆没有退出,自己花了一些时间研究了一下,这里将相关内容进行记录,基于Keyclaok 20的版本,实现springboot服务单点登录与退出

一、依赖

XML 复制代码
<!-- 在父工程中 -->
<dependencyManagement>
    <dependencies>
        <!-- 导入依赖 -->
        <dependency>
            <groupId>org.keycloak.bom</groupId>
            <artifactId>keycloak-adapter-bom</artifactId>
            <version>22.0.1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>


<!-- 在子工程中 -->
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>

    <dependency>
        <groupId>org.keycloak</groupId>
        <artifactId>keycloak-spring-boot-starter</artifactId>
    </dependency>

    <dependency>
        <groupId>org.keycloak</groupId>
        <artifactId>keycloak-spring-security-adapter</artifactId>
    </dependency>
</dependencies>

二、keycloak配置

这个是主要的,用设置拦截器实现登陆与退出

java 复制代码
package com.example.basic.conf;

import org.keycloak.KeycloakPrincipal;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
import org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount;
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@KeycloakConfiguration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class KeycloakSecurityConfiguration extends KeycloakWebSecurityConfigurerAdapter {

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

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

    @Bean
    public org.keycloak.adapters.KeycloakConfigResolver KeycloakConfigResolver() {
        return new KeycloakSpringBootConfigResolver();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        http
            .logout()
                 //拦截logout请求
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                .addLogoutHandler(keycloakLogoutHandler())
                .logoutSuccessHandler(logoutSuccessHandler())
                .deleteCookies("JSESSIONID")
            .and()
             //设置哪些可以忽略掉授权
            .authorizeRequests()
                .antMatchers("/user/login", "/token/generate",
                    "/access/**", "/js/**","/css/**","/fonts/**", "/index.html", "/error").permitAll()
                 //除了上面忽略掉授权请求,剩下所有必须经过授权才可以访问
                .antMatchers("/**").authenticated()
            .and().cors()
            .and().csrf().disable();
    }

    //处理logout自动跳转请求
    private LogoutSuccessHandler logoutSuccessHandler() {

        return new LogoutSuccessHandler() {
            @Override
            public void onLogoutSuccess(HttpServletRequest httpServletRequest,
                    HttpServletResponse httpServletResponse, Authentication authentication)
                    throws IOException, ServletException {
                KeycloakAuthenticationToken keycloakAuthenticationToken = (KeycloakAuthenticationToken)authentication;
                KeycloakSecurityContext keycloakSecurityContext =
                        keycloakAuthenticationToken.getAccount().getKeycloakSecurityContext();

                String idTokenHint = keycloakSecurityContext.getIdTokenString();
                String issuer = keycloakSecurityContext.getIdToken().getIssuer();
                String keycloakBaseUrl = issuer + "/protocol/openid-connect/logout";
                String postLogoutRedirectUri = httpServletRequest.getScheme() + "://" + httpServletRequest.getHeader("host");

                String logoutUrl = keycloakBaseUrl + "?post_logout_redirect_uri=" + postLogoutRedirectUri + "&id_token_hint=" + idTokenHint;
                // Do logout by redirecting to Keycloak logout
                httpServletResponse.sendRedirect(logoutUrl);
            }
        };
    }
}
相关推荐
Patrick在香港4 小时前
Python Docker镜像从1.2GB到89MB:多阶段构建的完整优化实录
java·python·docker·信息可视化·容器·数据分析·ai编程
上海安当技术4 小时前
敏感数据怎么防拖库?信封加密(DEK+KEK 二层密钥)架构设计与 Java 实战
java·开发语言·python
我是唐青枫4 小时前
Java JCommander 实战详解:用注解解析命令行参数
java·开发语言
大鹏说大话4 小时前
C++ 内存布局详解:类、虚函数、虚表底层原理
java·开发语言
还是鼠鼠5 小时前
Spring AI连接DeepSeek与通义千问:application.yaml配置详解
java·通义千问·spring ai·deepseek
计算机小白一个6 小时前
蓝桥杯 Java B 组之哈希表应用(两数之和、重复元素判断)
java·数据结构·算法·蓝桥杯
sunburn-7 小时前
Java 队列全面详解:从入门到面试实战
java·开发语言·汇编·ide·idea
vx-程序开发7 小时前
springboot农产品运输服务平台---附源码75498
java·javascript·spring boot·python·eclipse·django·php
攻城有术7 小时前
专项攻克——spring、springMVC、springBoot、springCloud的启动流程
spring boot·spring·spring cloud
独行侠影a7 小时前
SpringBoot 分布式锁实战:Redisson 解决订单超卖并发问题
spring boot·分布式·后端