Spring Security对接OIDC(OAuth2)外部认证

2024-02-20 09:28

本文主要是介绍Spring Security对接OIDC(OAuth2)外部认证,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前后端分离项目对接OIDC(OAuth2)外部认证,认证服务器可以使用Keycloak。

后端已有用户管理和权限管理,需要外部认证服务器的用户名和业务系统的用户名一致才可以登录。

后台基于Spring Boot 2.7 + Spring Security

流程:

  1. 前台浏览器跳转到  后台地址 + /login/oauth2/authorization/my-oidc-client
  2. 后台返回302重定向,重定向到登录外部认证服务器 http://my-oidc-provider.com
  3. 在外部认证网页登录成功后,自动重定向到前台地址 http://localhost/login ,前台取得URL中的参数,使用这些参数发送ajax post请求到  后台地址 + /login/oauth2/my-oidc-client
  4. 后台会自动与 http://my-oidc-provider.com 交互完成登录,并使用用户名取得本地用户信息后返回json
  5. 如果第4步失败,则返回自定义的错误信息json
     

(1)引入依赖:

org.springframework.boot:spring-boot-starter-oauth2-client

(2)配置文件:


spring.security.oauth2.client.registration.my-oidc-client.provider=my-oidc-provider
spring.security.oauth2.client.registration.my-oidc-client.client-id=my-client-id
spring.security.oauth2.client.registration.my-oidc-client.client-secret=my-client-secret
spring.security.oauth2.client.registration.my-oidc-client.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.my-oidc-client.scope=openid,profile
spring.security.oauth2.client.registration.my-oidc-client.redirect-uri=http://localhost/login
spring.security.oauth2.client.provider.my-oidc-provider.issuer-uri=http://my-oidc-provider.com

(3)Spring Security配置类:

package com.example.demo.config;import java.io.IOException;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken;
import org.springframework.security.oauth2.client.oidc.web.logout.OidcClientInitiatedLogoutSuccessHandler;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;@Configuration
@EnableWebSecurity
public class MyOAuth2SecurityConfig {private final UserDetailsService userDetailsService;private final ClientRegistrationRepository clientRegistrationRepository;private final ObjectMapper objectMapper;public MyOAuth2SecurityConfig(UserDetailsService userDetailsService, ClientRegistrationRepository clientRegistrationRepository, ObjectMapper objectMapper) {this.userDetailsService = userDetailsService;this.clientRegistrationRepository = clientRegistrationRepository;this.objectMapper = objectMapper;}@Beanpublic SecurityFilterChain oauth2SecurityFilterChain(HttpSecurity http) throws Exception {http.authorizeHttpRequests(httpRequests -> httpRequests.anyRequest().authenticated()).oauth2Login(oauth2Login -> oauth2Login.authorizationEndpoint(authorization -> authorization.baseUri("/login/oauth2/authorization")).loginProcessingUrl("/login/oauth2/*").successHandler(new MyAuthenticationSuccessHandler()).failureHandler(new MyAuthenticationFailureHandler()).addObjectPostProcessor(new ObjectPostProcessor<OAuth2LoginAuthenticationFilter>() {@Overridepublic <O extends OAuth2LoginAuthenticationFilter> O postProcess(O filter) {filter.setAuthenticationResultConverter(new Converter<OAuth2LoginAuthenticationToken,OAuth2AuthenticationToken>() {@Overridepublic OAuth2AuthenticationToken convert(OAuth2LoginAuthenticationToken source) {OidcUser user = (OidcUser) source.getPrincipal();String userName = user.getAttribute("preferred_username");// 根据用户名获取适用于本系统的用户对象,用户对象同时实现UserDetails和OidcUser接口UserDetails myUser = userDetailsService.loadUserByUsername(userName);// 用户对象保存IdToken用于退出登录// myUser.setIdToken(user.getIdToken());return new OAuth2AuthenticationToken((OidcUser) myUser, myUser.getAuthorities(), source.getClientRegistration().getRegistrationId());}});return filter;}})).formLogin(formLogin -> formLogin.disable()).logout(logout -> logout.logoutUrl("/logout").invalidateHttpSession(true).deleteCookies("SESSION").logoutSuccessHandler(this.logoutSuccessHandler())).csrf(csrf -> csrf.disable());return http.build();}private LogoutSuccessHandler logoutSuccessHandler() {OidcClientInitiatedLogoutSuccessHandler handler = new OidcClientInitiatedLogoutSuccessHandler(this.clientRegistrationRepository);handler.setPostLogoutRedirectUri(this.clientRegistrationRepository.findByRegistrationId("my-oidc-client").getRedirectUri());return handler;}class MyAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws JsonProcessingException, IOException {response.setStatus(HttpServletResponse.SC_OK);response.setContentType("application/json;charset=UTF-8");// 这里自定义返回的json对象内容response.getWriter().write(objectMapper.writeValueAsString(authentication.getPrincipal()));response.getWriter().flush();response.getWriter().close();}}class MyAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {@Overridepublic void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,AuthenticationException exception) throws IOException, ServletException {response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);response.setContentType("application/json;charset=UTF-8");// 这里自定义返回的json对象内容response.getWriter().write(objectMapper.writeValueAsString(""));response.getWriter().flush();response.getWriter().close();}}
}

这篇关于Spring Security对接OIDC(OAuth2)外部认证的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/727751

相关文章

SpringBoot路径映射配置的实现步骤

《SpringBoot路径映射配置的实现步骤》本文介绍了如何在SpringBoot项目中配置路径映射,使得除static目录外的资源可被访问,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一... 目录SpringBoot路径映射补:springboot 配置虚拟路径映射 @RequestMapp

Java MCP 的鉴权深度解析

《JavaMCP的鉴权深度解析》文章介绍JavaMCP鉴权的实现方式,指出客户端可通过queryString、header或env传递鉴权信息,服务器端支持工具单独鉴权、过滤器集中鉴权及启动时鉴权... 目录一、MCP Client 侧(负责传递,比较简单)(1)常见的 mcpServers json 配置

GSON框架下将百度天气JSON数据转JavaBean

《GSON框架下将百度天气JSON数据转JavaBean》这篇文章主要为大家详细介绍了如何在GSON框架下实现将百度天气JSON数据转JavaBean,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录前言一、百度天气jsON1、请求参数2、返回参数3、属性映射二、GSON属性映射实战1、类对象映

Java Stream 并行流简介、使用与注意事项小结

《JavaStream并行流简介、使用与注意事项小结》Java8并行流基于StreamAPI,利用多核CPU提升计算密集型任务效率,但需注意线程安全、顺序不确定及线程池管理,可通过自定义线程池与C... 目录1. 并行流简介​特点:​2. 并行流的简单使用​示例:并行流的基本使用​3. 配合自定义线程池​示

从原理到实战解析Java Stream 的并行流性能优化

《从原理到实战解析JavaStream的并行流性能优化》本文给大家介绍JavaStream的并行流性能优化:从原理到实战的全攻略,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的... 目录一、并行流的核心原理与适用场景二、性能优化的核心策略1. 合理设置并行度:打破默认阈值2. 避免装箱

解决升级JDK报错:module java.base does not“opens java.lang.reflect“to unnamed module问题

《解决升级JDK报错:modulejava.basedoesnot“opensjava.lang.reflect“tounnamedmodule问题》SpringBoot启动错误源于Jav... 目录问题描述原因分析解决方案总结问题描述启动sprintboot时报以下错误原因分析编程异js常是由Ja

Java Kafka消费者实现过程

《JavaKafka消费者实现过程》Kafka消费者通过KafkaConsumer类实现,核心机制包括偏移量管理、消费者组协调、批量拉取消息及多线程处理,手动提交offset确保数据可靠性,自动提交... 目录基础KafkaConsumer类分析关键代码与核心算法2.1 订阅与分区分配2.2 拉取消息2.3

SpringBoot集成XXL-JOB实现任务管理全流程

《SpringBoot集成XXL-JOB实现任务管理全流程》XXL-JOB是一款轻量级分布式任务调度平台,功能丰富、界面简洁、易于扩展,本文介绍如何通过SpringBoot项目,使用RestTempl... 目录一、前言二、项目结构简述三、Maven 依赖四、Controller 代码详解五、Service

Java中HashMap的用法详细介绍

《Java中HashMap的用法详细介绍》JavaHashMap是一种高效的数据结构,用于存储键值对,它是基于哈希表实现的,提供快速的插入、删除和查找操作,:本文主要介绍Java中HashMap... 目录一.HashMap1.基本概念2.底层数据结构:3.HashCode和equals方法为什么重写Has

Java 正则表达式的使用实战案例

《Java正则表达式的使用实战案例》本文详细介绍了Java正则表达式的使用方法,涵盖语法细节、核心类方法、高级特性及实战案例,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 目录一、正则表达式语法详解1. 基础字符匹配2. 字符类([]定义)3. 量词(控制匹配次数)4. 边