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();}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/691204.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++面试宝典第30题:分发饼干

题目 假设你是一位非常棒的家长,想要给你的孩子们分发一些小饼干。但是,每个孩子最多只能给一块饼干。对每一个孩子i,都有一个胃口值gi,这是能让孩子们满足胃口的饼干的最小尺寸。对每一块饼干j,都有一个尺寸sj。如果sj >= gi,我们就可以将这个饼干j分配给孩子i,这个…

golangci-lint如何关闭typecheck

https://github.com/golangci/golangci-lint/issues/2912 typecheck是go源码的校验&#xff0c;无法通过.golangci.yml配置关闭 可以直接在golangci-lint源码层面关闭typecheck

Springboot AOP开发

Springboot AOP开发 一 AOP概述 AOP&#xff0c;即面向切面编程&#xff0c;简言之&#xff0c;面向方法编程。 针对方法&#xff0c;在方法的执行前或执行后使用&#xff0c;用于增强方法&#xff0c;或拓展。 二 AOP开发 1.引入 spring-boot-starter-aop 在SpringBoot项…

AWS Elastic Beanstalk通过应用负载均衡配置https

接上一篇&#xff0c;今天说说怎么通过AWS Elastic Beanstalk提供的应用负载均衡配置https。 首先创建应用和环境&#xff0c;这里应用可以使用上一篇文章中使用的demo应用&#xff08;只需要package.json和app.js文件&#xff09; 创建环境的时候&#xff0c;确认下面两个参…

【高效开发工具系列】PyCharm使用

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

自养号测评低成本高效率推广,安全可控

测评的作用在于让用户更真实、清晰、快捷地了解产品以及产品的使用方法和体验。通过买家对产品的测评&#xff0c;也可以帮助厂商和卖家优化产品缺陷&#xff0c;提高用户的使用体验。这进而帮助他们获得更好的销量&#xff0c;并更深入地了解市场需求。因此&#xff0c;测评在…

基于单片机的智能宠物喂食器设计

摘要:阐述智能宠物喂食器的实现方式,以STC89C52单片机为核心芯片,控制LCD的显示、语音芯片的启动和步进电机的运行。通过按键设置预设时间,当时间到达预设时间时,语音电路发出提示,步进电机工作,提供食物。此系统解决了主人由于各种原因不在家,使得宠物不能按时吃饭的问…

ACL 2024系统

文章目录 ACL官方网站信息通知ACL2024 官方模版 ACL官方网站信息通知 https://2024.aclweb.org/ ACL2024 官方模版 https://github.com/acl-org/acl-style-files

【Java中23种设计模式-单例模式2--懒汉式线程不安全】

加油&#xff0c;新时代打工人&#xff01; 今天&#xff0c;重新回顾一下设计模式&#xff0c;我们一起变强&#xff0c;变秃。哈哈。 23种设计模式定义介绍 Java中23种设计模式-单例模式 package mode;/*** author wenhao* date 2024/02/19 09:16* description 单例模式--懒…

.NET高级面试指南专题九【 泛型概念,常用泛型类和方法,泛型约束,协变与逆变】

C#中的泛型&#xff08;Generics&#xff09;是一种强大的编程特性&#xff0c;它允许你在编写代码时使用不特定数据类型&#xff0c;而在编译时确定这些数据类型。泛型使得代码更加灵活、可重用&#xff0c;并提高了类型安全性。 功能和原理 泛型允许你编写能够与不同数据类型…

数字孪生核心技术揭秘(五):BIM究竟是解药还是毒药?

一、关于BIM的那些幻想 1.1 BIM是“数字孪生城市”最后一块拼图&#xff1f; 近几年&#xff0c;CIM概念越来越流行&#xff0c;已经成为数字孪生城市的主流数据模型。CIM原始概念指的是“城市信息模型”&#xff1b;2015年同济大学吴志强院士基于CIM概念提出“城市智慧模型”&…

如何用ChatGPT绘图?

详情点查看公众号&#xff1a;技术科研吧 链接&#xff1a;如何用ChatGPT绘图&#xff1f; 一&#xff1a;AI领域最新技术 1.OpenAI新模型-GPT-5 2.谷歌新模型-Gemini Ultra 3.Meta新模型-LLama3 4.科大讯飞-星火认知 5.百度-文心一言 6.MoonshotAI-Kimi 7.智谱AI-GLM-…

23种设计模式-Golang(完整版)

23种设计模式-Golang 完整代码链接&#xff1a;https://github.com/ziyifast/easy_design_mode &#x1f680;&#xff1a;欢迎star哦&#xff5e; 1 创建型模式 1.1 简单工厂模式&#xff08;simple factory&#xff09;&#xff1a;不同协议有生成不同downloader ①解析 go…

ChatGPT在数据分析学习阶段的应用

ChatGPT在数据分析学习阶段的应用 ​ 这个阶段&#xff0c;核心是三件事&#xff1a;制定学习计划、确定学习资料以及学习策略。我们可以自己完成这几件事&#xff0c;当然也可以借助ChatGPT来高效地达到目的。 1.1 制定学习计划 ​ 学习阶段的第一件事是制定学习计划&#…

USACO 2024年1月铜组 MAJORITY OPINION

第一题&#xff1a;MAJORITY OPINION 标签&#xff1a;思维、模拟 题意&#xff1a;给定一个长度为 n n n的序列 a a a&#xff0c;操作&#xff1a;若区间 [ i , j ] [i,j] [i,j]内某个数字 k k k出现的次数 大于区间长度的一半&#xff0c;可以将区间内的所有数都换成这个数…

python之元类

最近刚好在准备面试&#xff0c;然后复习知识点。看了好多元类相关的文章&#xff0c;但还是心存疑惑&#x1f914;。 还是写点东西吧&#xff01; 元类&#xff0c;官方的定义是&#xff0c;类的类型。而类型的顶点&#xff0c;便是type metaclass - The class of a class.…

Java流程控制

1. 流程控制 在一个程序中&#xff0c;有很多的代码&#xff0c;代码的执行顺序&#xff0c;就是流程。 用于控制代码流程的方式&#xff0c;就是流程控制 流程控制的分类&#xff1a; 顺序结构&#xff1a;代码从上到下&#xff0c;从右到左依次执行。 分支结构&#xff1a…

OpenAI的Sora的优点

OpenAI的Sora的优点主要包括以下几个方面&#xff1a; 1.强大的视频生成能力&#xff1a;Sora可以根据用户的文本提示或静态图像生成高质量、逼真的视频。它继承了DALL-E 3的画质和遵循指令能力&#xff0c;能够生成具有多个角色、包含特定运动的复杂场景&#xff0c;几乎达到…

Unity3d Mesh篇(一)— 创建简单三角面

文章目录 前言一、Mesh组成二、使用步骤三、效果四、总结 前言 Mesh&#xff08;网格&#xff09;是一种常用的3D图形表示方法&#xff0c;它由顶点&#xff0c;法线&#xff0c;UV 坐标&#xff0c;和三角形等组成。您可以使用 Mesh 类的方法来创建或修改网格&#xff0c;也可…

k8s学习(RKE+k8s+rancher2.x)成长系列之简配版环境搭建(三)

3.19.切换RKE用户&#xff0c;并做免密登录&#xff08;三台机器相互免密&#xff09; su rke cd~ ssh-keygen[rkemaster.ssh]$ssh-copy-id rkeslaver2 [rkemaster.ssh]$ssh-copy-id rkeslaver1 [rkemaster.ssh]$ssh-copy-id rkemaster3.20.搭建RKE集群 为了方便理解&#…