当前位置: 首页 > news >正文

基于 Spring Security OAuth2 + JWT 实现 SSO

单点登录(Single Sign-On,SSO)是一种身份认证机制,允许用户只需登录一次,即可访问多个相互信任的应用系统,无需重复登录。在分布式系统中,SSO 是提升用户体验和系统安全性的核心方案。

SSO 核心原理

  1. 认证中心(Identity Provider,IdP):统一的登录入口,负责用户身份验证并颁发令牌(如 JWT)。
  2. 服务提供商(Service Provider,SP):各个业务系统,信任认证中心颁发的令牌,无需重复验证用户身份。
  3. 令牌机制:认证中心验证用户身份后,生成加密令牌(如 JWT),用户访问其他系统时携带令牌,SP 验证令牌有效性即可信任用户。

基于 Spring Security OAuth2 + JWT 实现 SSO

结合前面的 OAuth2 + JWT 整合方案,扩展实现 SSO 的核心步骤如下:

1. 架构设计
  • 认证中心(Authorization Server):独立部署,负责用户登录、令牌颁发(JWT)、令牌验证。
  • 多个资源服务器(Resource Server):各业务系统(如订单系统、用户系统),配置信任认证中心的 JWT 令牌。
  • 共享会话:通过 JWT 令牌在各系统间共享用户身份信息(无需共享 Session)。
2. 认证中心配置(关键扩展)

认证中心需支持授权码模式(authorization_code)(适合 SSO 场景,安全性高),并确保 JWT 令牌可被所有 SP 验证。

@Configuration
@EnableAuthorizationServer
public class SsoAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate UserDetailsService userDetailsService;@Autowiredprivate JwtTokenUtil jwtTokenUtil;// 配置客户端(各SP系统需在认证中心注册)@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.inMemory()// 客户端1(如订单系统).withClient("order-service").secret(passwordEncoder().encode("order-secret")).authorizedGrantTypes("authorization_code", "refresh_token") // 授权码模式.redirectUris("http://localhost:8081/login/oauth2/code/order-service") // 回调地址(SP的地址).scopes("read", "write").accessTokenValiditySeconds(3600)// 客户端2(如用户系统).and().withClient("user-service").secret(passwordEncoder().encode("user-secret")).authorizedGrantTypes("authorization_code", "refresh_token").redirectUris("http://localhost:8082/login/oauth2/code/user-service").scopes("read", "write").accessTokenValiditySeconds(3600);}// JWT令牌转换器(确保所有SP使用相同密钥验证)@Beanpublic JwtAccessTokenConverter accessTokenConverter() {JwtAccessTokenConverter converter = new JwtAccessTokenConverter();converter.setSigningKey(jwtTokenUtil.SECRET); // 所有系统共享的签名密钥return converter;}// 令牌存储(JWT)@Beanpublic TokenStore tokenStore() {return new JwtTokenStore(accessTokenConverter());}@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) {endpoints.authenticationManager(authenticationManager).userDetailsService(userDetailsService).tokenStore(tokenStore()).accessTokenConverter(accessTokenConverter());}// 允许跨域(可选,根据SP部署情况配置)@Overridepublic void configure(AuthorizationServerSecurityConfigurer security) {security.tokenKeyAccess("permitAll()") // 允许获取公钥(用于验证JWT).checkTokenAccess("isAuthenticated()");}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}
}
3. 服务提供商(SP)配置

每个业务系统(SP)需配置为资源服务器,并信任认证中心的 JWT 令牌。

order-service(端口 8081)为例:

java

运行

@Configuration
@EnableResourceServer
@EnableWebSecurity
public class OrderServiceConfig extends ResourceServerConfigurerAdapter {@Autowiredprivate JwtTokenUtil jwtTokenUtil;// 资源ID(需与认证中心客户端配置对应)private static final String RESOURCE_ID = "order-service";@Overridepublic void configure(ResourceServerSecurityConfigurer resources) {resources.resourceId(RESOURCE_ID).tokenStore(tokenStore()) // 使用JWT验证令牌.stateless(true); // 无状态(不存储Session)}// 配置JWT令牌验证@Beanpublic TokenStore tokenStore() {JwtAccessTokenConverter converter = new JwtAccessTokenConverter();converter.setSigningKey(jwtTokenUtil.SECRET); // 与认证中心共享密钥return new JwtTokenStore(converter);}// 配置访问规则@Overridepublic void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/public/**").permitAll().anyRequest().authenticated().and().csrf().disable(); // 前后端分离场景可禁用CSRF}
}
4. SSO 登录流程
  1. 用户访问 SP:用户访问http://localhost:8081/order(订单系统),未登录则被重定向到认证中心。

  2. 认证中心登录:重定向至认证中心登录页http://localhost:8080/oauth/authorize?client_id=order-service&response_type=code&redirect_uri=http://localhost:8081/login/oauth2/code/order-service,用户输入账号密码。

  3. 颁发授权码:认证中心验证通过后,生成授权码(code),并重定向回 SP 的回调地址(如http://localhost:8081/login/oauth2/code/order-service?code=xxx)。

  4. SP 获取令牌:SP 使用授权码向认证中心请求令牌:

    POST http://localhost:8080/oauth/token
    Content-Type: application/x-www-form-urlencoded
    Authorization: Basic b3JkZXItc2VydmljZTpvcmRlci1zZWNyZXQ=grant_type=authorization_code&code=xxx&redirect_uri=http://localhost:8081/login/oauth2/code/order-service
    

    认证中心返回 JWT 格式的access_token

  5. SP 验证令牌:SP 解析 JWT 令牌,获取用户信息,允许访问资源。

  6. 访问其他 SP:用户访问http://localhost:8082/user(用户系统)时,同样重定向到认证中心,但认证中心发现用户已登录,直接颁发授权码,用户无需重复输入密码。

5. 关键优化
  • 统一登录页:认证中心提供统一的登录界面,保持用户体验一致。
  • 令牌刷新:通过refresh_token机制,避免用户频繁登录。
  • 单点登出:认证中心需提供登出接口,清除用户会话,并通知所有 SP 失效令牌(可选,实现复杂,通常通过令牌过期机制简化)。
  • HTTPS 传输:所有步骤必须使用 HTTPS,防止令牌和授权码被窃取。

与传统 Session 共享的区别

方案原理优点缺点
传统 Session 共享多系统共享同一个 Session 存储实现简单(如 Redis 共享 Session)耦合性高,分布式场景扩展性差
OAuth2 + JWT SSO基于令牌的无状态认证松耦合,支持跨域、跨语言,扩展性强令牌需加密,登出实现复杂

总结

基于 Spring Security OAuth2 + JWT 的 SSO 方案,通过认证中心统一颁发 JWT 令牌,各服务提供商验证令牌有效性,实现了 “一次登录,多系统访问” 的目标。核心是确保令牌安全(签名 + HTTPS) 和各系统信任统一的认证中心

实际项目中,可结合 Spring Cloud Security 简化配置,并使用 Redis 存储令牌黑名单(用于主动登出)。

为什么不建议直接用JWT实现单点登陆?

使用 JWT 实现单点登录(SSO)有其优势,但也存在局限性,是否 “好” 取决于具体场景。以下从 JWT 实现 SSO 的特点、适用场景,以及更优的 SSO 技术方案两方面展开分析:

一、JWT 实现单点登录的优缺点

优点:
  1. 无状态:JWT 自身包含用户身份信息,服务端无需存储会话状态,减轻了 SSO 服务器的存储压力,适合分布式系统。
  2. 跨域友好:JWT 通常通过 HTTP 头部(如 Authorization)传递,天然支持跨域场景,无需依赖 Cookie 的同源限制。
  3. 实现简单:无需复杂的会话同步机制,客户端携带 JWT 即可完成身份验证,开发成本较低。
缺点:
  1. 无法即时吊销:JWT 一旦签发,在有效期内无法主动废除(除非结合黑名单机制,但会破坏无状态特性),若用户注销或令牌泄露,风险会持续到过期。
  2. 安全性依赖签名:需确保签名密钥安全,一旦泄露,攻击者可伪造令牌;且 JWT payload 是 Base64 编码(非加密),敏感信息需额外加密。
  3. 令牌体积可能过大:若携带过多用户信息,会增加请求开销,影响性能。

二、更推荐的单点登录技术方案

单点登录的核心是 “一次认证,多系统信任”,技术选型需结合安全性、可扩展性、实时性等需求,主流方案如下:

1. OAuth 2.0 + OpenID Connect(OIDC)
  • 适用场景:第三方登录(如微信、GitHub 登录)、企业内部多系统 SSO、需要细粒度权限控制的场景。
  • 优势
    • OIDC 在 OAuth 2.0 基础上增加了身份层,通过 ID Token(JWT 格式)标准化用户身份信息,同时支持 Access Token 控制资源访问。
    • 支持多种授权模式(如授权码模式、密码模式),安全性高,适合复杂场景。
    • 可通过令牌撤销端点(Token Revocation)主动吊销令牌,解决 JWT 无法即时失效的问题。
  • 缺点:协议较复杂,实现成本较高。
2. 基于 Session + 中央认证服务器(CAS)
  • 适用场景:企业内部系统(如办公系统、ERP 等),对安全性和实时性要求高,且系统技术栈统一(如均为 Web 应用)。
  • 优势
    • 经典的 SSO 方案,流程成熟:用户在 CAS 服务器登录后,各子系统通过 CAS 验证票据(Ticket)获取身份,会话集中管理。
    • 支持即时注销:注销时 CAS 服务器可通知所有子系统销毁本地会话,安全性强。
  • 缺点:依赖 Cookie 传递会话,跨域支持较弱;子系统需与 CAS 服务器交互验证票据,可能增加网络开销。
3. JWT + 黑名单机制(折中方案)
  • 适用场景:对无状态要求高、用户规模不大、令牌有效期短(如 15 分钟)的场景(如移动端 API 服务)。
  • 优化点:通过 Redis 维护已吊销的 JWT 黑名单,验证时先检查黑名单,平衡无状态和安全性,但会增加服务端少量存储和查询成本。

三、总结

  • 不推荐单独用 JWT 做 SSO:主要问题是无法即时吊销,安全性风险较高,仅适合低安全需求、短令牌有效期的场景。
  • 首选方案OAuth 2.0 + OIDC,通用性强、安全性高,支持第三方登录和复杂权限控制,是目前行业主流的 SSO 标准(如 Google、Facebook 登录均基于此)。
  • 备选方案:若为企业内部封闭系统,CAS 更简单可控;若需无状态且能接受黑名单开销,可考虑 JWT + 黑名单。
http://www.dtcms.com/a/431205.html

相关文章:

  • 数智经济时代医疗领域医学影像系统现状与趋势研究:多模态融合技术方向
  • 解读 2025 《高质量数据集 分类指南》
  • 为什么说这个是6dB de-emphasis”(即“6dB去加重”)--Con‘t
  • Eclipse 快捷键
  • 樟木头网站网络安全维护公司
  • 【EE初阶 - 网络原理】网络通信
  • 方案网站有哪些盗用别的公司网站模块
  • 做网站是否要去工商备案做网站群
  • Less resolver error:‘~antd/es/style/themes/index.less‘ wasn‘t found.
  • php网站验证码错误网站改版对用户的影响
  • vue中如何实现异步加载组件
  • 网站地图seo石城网站建设
  • 怎么防止网站被镜像wordpress seo 主题
  • 那些钓鱼网站是怎么做的页面设计上边距在哪里找
  • 中国移动idc建设网站wordpress 导航栏
  • @RequestBody与@PathVariable什么时候加
  • 2011 年真题配套词汇单词笔记(考研真相)
  • “AMQP协议深度解析:消息队列背后的通信魔法”之核心概念与SpringBoot落地实战
  • 网规答题点【summer解析】华为5G空口新技术有F-OFDM和SCMA,F-OFDM是基于OFDM的改进版本,可以 实现空口物理层分片,兼容LTE 4G。
  • 简约智能设备制造公司网站今天东营发生的重大新闻
  • Matrixport DAT与XBIT携DEX赋能生态,共赴新加坡TOKEN2049
  • 做网站需要什么营业执照中国建设企业协会网站首页
  • 微服务项目->在线oj系统(Java-Spring)--增删改(前端)
  • 软件网站开发评估免费拿货的代理商
  • C#基础05-控制语句
  • 网站域名过期还能用吗wordpress主题管理插件
  • 扩展BaseMapper类
  • 秦皇岛建设部网站工程建设信息都在哪个网站发布
  • 多模态分类:图文结合的智能识别与代码实战
  • UE5 - C++项目基础