Spring Boot项目中实现单点登录(SSO)完整指南
单点登录(Single Sign-On, SSO)是一种身份验证机制,允许用户使用一组凭证(如用户名和密码)登录多个相关但独立的系统。
一、单点登录的核心原理
SSO的核心原理使集中认证、分散授权,主要流程如下:
1.用户访问应用A
2.应用A检查本地会话,发现未登录
3.重定向到SSO认证中心
4.用户在认证中心登录
5.认证中心创建全局会话,并颁发令牌
6.用户携带令牌返回应用A
7.应用A向认证中心验证令牌
8.认证中心返回用户信息,应用A创建本地会话
9.用户访问应用B时重复2-8流程(但无需重复登录)
二、Spring Boot实现SSO的三种主流方案
方案1:基于OAuth2的实现(推荐)
1.添加依赖
<!-- Spring Security OAuth2 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
2.认证中心配置
@Configuration
@EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.inMemory().withClient("client1").secret(passwordEncoder().encode("secret1")).authorizedGrantTypes("authorization_code", "refresh_token").scopes("read", "write").redirectUris("http://localhost:8081/login/oauth2/code/client1").autoApprove(true);}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}
}
3.资源服务配置
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {@Overridepublic void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/api/**").authenticated().anyRequest().permitAll();}
}
4.客户端应用配置
# application.yml
spring:security:oauth2:client:registration:sso:client-id: client1client-secret: secret1authorization-grant-type: authorization_coderedirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"scope: read,writeprovider:sso:issuer-uri: http://localhost:8080
方案2:基于JWT实现
1.添加依赖
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version>
</dependency>
2.JWT工具类
public class JwtTokenUtil {private static final String SECRET = "your-secret-key";private static final long EXPIRATION = 86400000; // 24小时public static String generateToken(UserDetails userDetails) {return Jwts.builder().setSubject(userDetails.getUsername()).setIssuedAt(new Date()).setExpiration(new Date(System.currentTimeMillis() + EXPIRATION)).signWith(SignatureAlgorithm.HS512, SECRET).compact();}public static String getUsernameFromToken(String token) {return Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token).getBody().getSubject();}
}
3.认证过滤器
public class JwtAuthenticationFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {String token = resolveToken(request);if (token != null && validateToken(token)) {String username = JwtTokenUtil.getUsernameFromToken(token);UserDetails userDetails = userDetailsService.loadUserByUsername(username);UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));SecurityContextHolder.getContext().setAuthentication(authentication);}chain.doFilter(request, response);}private String resolveToken(HttpServletRequest request) {String bearerToken = request.getHeader("Authorization");if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {return bearerToken.substring(7);}return null;}
}
方案3:基于CAS实现
1.添加CAS客户端依赖
<dependency><groupId>org.jasig.cas.client</groupId><artifactId>cas-client-support-springboot</artifactId><version>3.6.4</version>
</dependency>
2.CAS配置
@Configuration
public class CasConfig {@Value("${cas.server.url}")private String casServerUrl;@Value("${cas.service.url}")private String serviceUrl;@Beanpublic FilterRegistrationBean<AuthenticationFilter> casAuthenticationFilter() {FilterRegistrationBean<AuthenticationFilter> registration = new FilterRegistrationBean<>();registration.setFilter(new AuthenticationFilter());registration.addInitParameter("casServerLoginUrl", casServerUrl + "/login");registration.addInitParameter("serverName", serviceUrl);registration.addUrlPatterns("/*");return registration;}@Beanpublic ServletListenerRegistrationBean<SingleSignOutHttpSessionListener> casSingleSignOutListener() {return new ServletListenerRegistrationBean<>(new SingleSignOutHttpSessionListener());}
}
三、SSO实现的关键技术点
1.会话管理
-
分布式会话:使用Redis存储会话信息
@Bean public RedisIndexedSessionRepository sessionRepository(RedisOperations<String, Object> redisOperations) {return new RedisIndexedSessionRepository(redisOperations); }
-
Session共享配置
spring:session:store-type: redisredis:flush-mode: on_savenamespace: spring:session
2.跨域问题解决
@Configuration
public class CorsConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOrigins("*").allowedMethods("GET", "POST", "PUT", "DELETE").allowedHeaders("*").allowCredentials(true).maxAge(3600);}
}
3.安全配置
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/login", "/oauth/**").permitAll().anyRequest().authenticated().and().formLogin().loginPage("/login").and().logout().logoutUrl("/logout").logoutSuccessUrl("/").invalidateHttpSession(true).deleteCookies("JSESSIONID");}
}
四、SSO实现的最佳实践
1.安全性考虑:
- 使用HTTPS加密所有通信
- 实现令牌的短期有效性(设置合理的过期时间)
- 防范CSRF攻击
2.性能优化:
- 使用缓存减少令牌验证的数据库查询
- 实现令牌的自动续期机制
3.用户体验:
- 实现无缝跳转,避免多次重定向
- 提供清晰的登录状态提示
4.监控与日志
- 记录所有认证事件
- 实现异常登录的告警机制
五、三种SSO方案对比
方案 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
OAuth2 | 标准协议,安全性高,扩展性强 | 实现复杂度较高 | 企业级应用,多平台集成 |
JWT | 无状态,性能好,适合分布式系统 | 令牌无法主动失效 | 微服务架构,前后端分离 |
CAS | 专为SSO设计,功能完善 | 需要额外部署CAS服务器 | 传统企业应用,教育系统 |
六、常见问题解决方案
1.令牌失效问题
- 实现令牌刷新机制
- 使用Redis黑名单管理已注销令牌
2.跨域会话问题
-
设置正确的Cookie域和路径
@Bean public CookieSerializer cookieSerializer() {DefaultCookieSerializer serializer = new DefaultCookieSerializer();serializer.setCookieName("JSESSIONID");serializer.setCookiePath("/");serializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$");return serializer; }
3.多因素认证集成
@Override
protected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/login").permitAll().antMatchers("/mfa-verify").hasRole("PRE_AUTH").anyRequest().fullyAuthenticated().and().formLogin().loginPage("/login").successHandler((request, response, authentication) -> {if (needsMfa(authentication)) {response.sendRedirect("/mfa-verify");} else {response.sendRedirect("/home");}});
}
相关文章:
Spring Boot项目中实现单点登录(SSO)完整指南
单点登录(Single Sign-On, SSO)是一种身份验证机制,允许用户使用一组凭证(如用户名和密码)登录多个相关但独立的系统。 一、单点登录的核心原理 SSO的核心原理使集中认证、分散授权,主要流程如下: 1.用户访问应用A 2.应用A检查本地会话&a…...

Windows环境下Redis的安装使用与报错解决
最近在做项目的时候需要用到Redis,本来没觉得是什么麻烦,下载安装使用一步到位的事,但紧随而来的问题,让我开始怀疑人生,再加上代码跑不出来,我还专门找人给我看看怎么个是,结果就是单纯的Redis…...

鸿蒙完整项目-仿盒马App(一)首页静态页面
跟着鸿蒙小林博主,练习下项目~记录下首页的搭建,后续继续完善和整体项目完成会进行布局修改,先按照博主的跟做,后续在改 1.分为底部整体框架搭建 2.首页布局(顶部搜索、新人专享、金刚区(两个不同集合数据)…...
大模型(4)——Agent(基于大型语言模型的智能代理)
大模型Agent是一种基于大型语言模型(LLM)的智能系统,能够自主感知环境、规划任务、调用工具并完成复杂目标。其核心原理是将大模型的推理能力与外部行动能力结合,实现从“思考”到“行动”的闭环。以下是其原理详解与实现方法&…...

39-居住证管理系统(小程序)
技术栈: springBootVueMysqlUni-app 功能点: 群众端 警方端 管理员端 群众端: 1.首页: 轮播图展示、公告信息列表 2.公告栏: 公告查看及评论 3.我的: 联系我们: 可在线咨询管理员问题 实时回复 居住证登记申请 回执单查看 领证信息查看 4.个人中心: 个人信息查看及修改…...

WPF【11_4】WPF实战-重构与美化(MVVM 架构)
11-9 【理论】MVVM 架构 在 WPF 项目中,我们主要采用的是一种类似 MVC 的架构,叫做 MVVM。 MVVM 继承了 MVC 的理念,是 Model-View-ViewModel 的缩写,中文意思是模型、视图、视图模型。这三个词分开看我们都能看懂,不…...

计算逆时针夹角(有向角度)——CAD c# 实现两条线(向量)的逆时针夹角
效果如下: 附部分代码如下: public void 逆时针夹角Demo(){// 获取当前 CAD 文档和编辑器Document doc Application.DocumentManager.MdiActiveDocument;Editor ed doc.Editor;Database db doc.Database;try{Point3d vec1Start, vec1End;if (!GetTwoP…...
鸿蒙OSUniApp 开发带有通知提示的功能组件#三方框架 #Uniapp
使用 UniApp 开发带有通知提示的功能组件 在移动应用开发中,通知提示(Notification/Toast/Alert)是提升用户体验和交互效率的重要手段。无论是表单校验、操作反馈、系统消息还是营销推送,合理的通知提示都能帮助用户及时获取关键…...
前端EXCEL插件智表ZCELL数据源功能详解
一、数据源功能介绍 前端EXCEL插件智表ZCELL提供了强大的数据源管理功能,使开发者能够灵活地在电子表格中集成和管理结构化数据。数据源功能主要分为两种类型: 卡片式数据源:适合展示和编辑单个数据记录 表格式数据源:适合处理表…...
打卡第31天:模块和库的导入
重复内容 知识点回顾: 1.导入官方库的三种手段 2.导入自定义库/模块的方式 3.导入库/模块的核心逻辑:找到根目录(python解释器的目录和终端的目录不一致) 作业:自己新建几个不同路径文件尝试下如何导入 导入机制的核…...
LLM Coding
AI Coding 深度解析:探索编程新范式与未来趋势 | w3cschool笔记https://www.phodal.com/blog/ai-friendly-architecture/bmadcode/BMAD-METHOD: Breakthrough Method for Agile Ai Driven Development...
Qt 的多线程
Qt 中的多线程主要用于处理耗时操作,避免阻塞主线程(UI 线程),从而提高程序的响应性和运行效率。以下是 Qt 多线程的相关技术总结: 常见的多线程实现方式 继承 QThread 类 :最基础的实现方式,具体步骤为继承 QThread 类,重写其 run() 函数,在 run() 函数中编写线程要…...
【请关注】各类MySQL数据备份还原分享
MySQL数据备份的全部方法 MySQL数据备份是数据库管理中的关键任务,以下是MySQL数据备份的全面方法总结: 一、逻辑备份方法 1. **mysqldump工具** - 最常用的备份工具 - 命令示例: >bash mysqldump -u [username] -p[password] [database_name] > backup.sql > -…...
Go语言方法与接收者 -《Go语言实战指南》
在 Go 中,方法是绑定到某个类型上的函数。与普通函数不同,方法具有一个“接收者(receiver)”,用于指定它是哪个类型的“方法”。 一、方法的定义语法 func (接收者名 接收者类型) 方法名(参数列表) 返回值列表 {// 方…...
基于 STM32 的农村污水处理控制系统设计与实现
摘要 针对农村污水处理自动化程度低、运维成本高的问题,本文设计了一种基于 STM32 单片机的污水处理控制系统。系统通过多传感器实时监测水质参数,结合 PID 控制算法实现污水处理全流程自动化,并集成远程监控功能,满足农村地区低成本、易维护的需求。 一、硬件系统设计 …...

【Linux】进程 信号的产生
🌻个人主页:路飞雪吖~ 🌠专栏:Linux 目录 一、掌握Linux信号的基本概念 🌠前台进程 VS 后台进程 🌠 小贴士: 🪄⼀个系统函数 --- signal() 🪄查看信号 --- man 7 sign…...
实时操作系统革命:实时Linux驱动的智能时代底层重构
一、智能时代对实时性的终极挑战 在万物互联的智能时代,人类对机器响应速度的期待已突破物理极限。当工业机器人以亚毫米级精度执行微米级加工任务,当自动驾驶系统在130公里时速下需在10毫秒内完成决策切换,当医疗机器人需在5毫秒内响应神经…...
NGINX HTTP/3 实验指南安装、配置与调优
一、HTTP/3 简介 基于 QUIC:在 UDP 之上实现的多路复用传输,内置拥塞控制与前向纠错,无需三次握手即可恢复连接。零 RTT 重连:借助 TLS 1.3,实现连接恢复时的 0-RTT 数据发送(视底层库支持)。多…...

机器学习中的维度、过拟合、降维
1. 维度灾难 当我们谈论机器学习模型在处理数据时遇到的困难,一个常常被提及的词便是“维度灾难”(Curse of Dimensionality)。这不是科幻小说里的情节,而是数学和计算世界里真实存在的困境。它指的正是:当数据集的特…...

关于git的使用
下载git 可以去git的官网下载https://git-scm.com/downloads 也可以去找第三方的资源下载,下载后是一个exe应用程序,直接点开一直下一步就可以安装了 右键任意位置显示这两个就代表成功,第一个是git官方的图形化界面,第二个是用…...

预约按摩小程序源码介绍
基于ThinkPHP、FastAdmin和UniApp开发的预约按摩小程序源码,ThinkPHP作为后端框架,以其高效稳定著称,能妥善处理数据逻辑与业务规则。FastAdmin作为后台管理框架,极大简化了后台管理系统的搭建与维护。UniApp则让小程序具备跨平台…...

Elasticsearch创建快照仓库报错处理
创建快照仓库报错: 根据报错提示的信息,问题可能出在 Elasticsearch 的配置中。当你尝试创建一个文件系统(fs)类型的快照仓库时,虽然已经指定了 location 参数,但 Elasticsearch 仍然报错,这通…...
LINUX安装运行jeelowcode前端项目
参考 JeeLowCode低代码社区,JeeLowCode低代码开发平台,JeeLowCode低代码开发框架,快速启动(VUE) 安装node 18 LINUX安装node/nodejs_linux安装node 安装到哪-CSDN博客 安装PNPM LINUX安装PNPM-CSDN博客 下载 git clone https://gitcode.com/jeelo…...

使用DDR4控制器实现多通道数据读写(十三)
一、概述 在上一章节中使用仿真简单验证了interconnect的功能,使用四个axi4的主端口同时发起读写命令,经过interconnect后,将这些读写指令依次发给ddr4控制器。Ddr4控制器响应后再依次将响应发送到各个通道。从而实现多通道读写ddr4控制器的功…...
如何描述BUG
一、如何描述BUG 1.1 版本信息 1.1.1 必填项 精确到构建版本号(如v2.3.1_build20240615) 获取方式: 代码版本控制系统(Git提交哈希值)应用内版本信息(App的About页面)持续集成工具生成的版本…...
Python进阶:如何通过组合模式实现高性能Vector类?
🔍 设计动机:为何抛弃继承选择组合? 在实现多维向量类Vector时,我们刻意采用组合模式而非继承,核心优势在于: 高扩展性:通过array数组存储分量,天然支持高维向量低耦合:…...

谷歌Veo vs Sora:AI视频生成技术的巅峰对决
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 ——从架构到实践,解析音画同步、物理模拟与长视频生成的破局之战 一、技术架构:双雄对垒,殊途同归? 谷歌…...

基于Spring boot+vue的中医养生系统的设计与实现(源码+论文+部署+安装+调试+售后)
感兴趣的可以先收藏起来,还有大家在毕设选题,项目以及论文编写等相关问题都可以给我留言咨询,我会一一回复,希望帮助更多的人。 系统背景 在健康中国战略持续推进与全民健康意识显著提升的时代背景下,中医养生作为中…...

31.第二阶段x64游戏实战-封包-线程发包
免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 本次游戏没法给 内容参考于:微尘网络安全 上一个内容:30.第二阶段x64游戏实战-认识网络数据包发送流程 代码跳转 ws2_32.send跳转sen…...

Unity数字人开发笔记
开源工程地址:https://github.com/zhangliwei7758/unity-AI-Chat-Toolkit 先致敬zhangliwei7758,开放这个源码 一、建立工程 建立Unity工程(UnityAiChat)拖入Unity-AI-Chat-Toolkit.unitypackage打开chatSample工程,可…...