SpringCloud之SSO单点登录-基于Gateway和OAuth2的跨系统统一认证和鉴权详解
单点登录(SSO)是一种身份验证过程,允许用户通过一次登录访问多个系统。本文将深入解析单点登录的原理,并详细介绍如何在Spring Cloud环境中实现单点登录。通过具体的架构图和代码示例,我们将展示SSO的工作机制和优势,帮助开发者更好地理解和应用这一技术。

一、单点登录简介
1、单点登录介绍
单点登录(Single Sign-On,简称SSO)是一种认证机制,允许用户通过一次身份验证后,访问多个相互信任的应用系统。它简化了用户的操作,提高了用户体验,同时也降低了管理多个认证系统的复杂性。在现代分布式系统和微服务架构中,SSO尤为重要,因为它可以减少重复的登录操作,统一用户认证入口,提高系统的安全性和可管理性。
2、单点登录原理
SSO的基本原理是通过共享认证状态来实现对多个系统的访问。其核心步骤包括:
- 用户认证:用户在SSO认证中心进行登录,认证中心验证用户身份后生成一个Token。
- Token共享:用户访问其他受信任的应用系统时,携带这个Token。应用系统通过验证Token来确认用户身份。
- 会话管理:SSO系统管理用户会话状态,确保用户在有效期内不需要重复登录。
3、单点登录架构图

二、单点登录实现
在Spring Cloud环境中实现单点登录需要考虑以下几个步骤:
| 步骤 | 描述 | 
|---|---|
| 1. 建立认证中心 | 创建一个专门的认证服务,负责用户登录和Token生成。可以使用Spring Security和OAuth2来实现这一功能。 | 
| 2. 配置网关服务 | 通过Spring Cloud Gateway或Zuul来实现请求路由和Token验证。 | 
| 3. 应用服务集成 | 将各个应用服务与认证中心集成,确保每个请求都经过Token验证。 | 
1. 建立认证中心
认证中心负责用户认证和Token生成。可以使用Spring Security和OAuth2来实现认证中心。
OAuth2 协议介绍:
OAuth2 协议是一种授权框架,允许第三方应用在用户授权下,访问用户的资源而无需共享用户的凭据,常用于社交媒体登录等场景。
OAuth2 协议一共支持四种不同的授权模式:
- 授权码模式:大多数第三方平台登录功能都采用这种模式,因其具有较高的安全性。
- 简化模式:简化模式不需要第三方服务器(客户端)的参与,直接在浏览器中向授权服务器申请令牌(token)。如果网站是纯静态页面,可以采用这种方式。
- 密码模式:密码模式要求用户将用户名和密码直接提供给客户端,客户端再使用这些信息向授权服务器申请令牌(token)。这种模式需要用户对客户端有高度的信任,例如客户端应用和服务器提供商是同一家公司。
- 客户端模式:客户端模式是指客户端以自己的名义而非用户的名义向授权服务器申请授权。严格来说,客户端模式并不属于OAuth协议的典型解决方案,但在某些移动端授权服务器上使用这种模式对开发者来说非常方便。
最常用的是授权码模式,也是我们这里使用的模式。
OAuth2 授权码模式示意图:
为了更清晰地展示授权码模式的每个环节,我们可以使用Mermaid将流程分为几个部分。以下是分成四张图分别介绍每个环节的示例代码:
- Step 1: 用户请求资源并重定向到授权服务器

- Step 2: 用户同意授权并获取授权码

- Step 3: 客户端交换授权码获取访问令牌

- Step 4: 客户端使用访问令牌访问资源服务器

① 添加OAuth2依赖
给项目添加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>
<dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
② 配置OAuth2认证服务器
创建并配置OAuth2认证服务器:
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {@Autowiredprivate AuthenticationManager authenticationManager;@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.inMemory().withClient("client-id").secret("{noop}client-secret").authorizedGrantTypes("authorization_code", "refresh_token", "password").scopes("read", "write").redirectUris("http://localhost:8081/login/oauth2/code/custom");}@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.authenticationManager(authenticationManager).tokenStore(new InMemoryTokenStore());}
}
③ 配置Spring Security
创建并配置Spring Security:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication().withUser("user").password("{noop}password").roles("USER");}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated().and().formLogin().permitAll();}@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}
}
2. 配置网关服务
网关服务负责路由请求和验证Token。我们使用Spring Cloud Gateway来实现。
① 添加网关服务依赖
给项目添加网关服务依赖项:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
② 增加Gateway配置
在application.yml中添加Gateway配置:
spring:cloud:gateway:routes:- id: user-serviceuri: lb://USER-SERVICEpredicates:- Path=/user/**filters:- TokenRelaysecurity:oauth2:client:provider:custom:authorization-uri: http://localhost:8080/oauth/authorizetoken-uri: http://localhost:8080/oauth/tokenuser-info-uri: http://localhost:8080/userinfojwk-set-uri: http://localhost:8080/.well-known/jwks.jsonregistration:custom:client-id: client-idclient-secret: client-secretauthorization-grant-type: authorization_coderedirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"scope: read,write
3. 应用服务集成
每个微服务都需要配置为资源服务器,以确保每个请求都经过Token验证。
① 给每个服务添加依赖
给每个服务添加OAuth2资源服务器依赖项:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
② 给每个服务添加配置
在application.yml中添加OAuth2资源服务器配置:
spring:security:oauth2:resourceserver:jwt:issuer-uri: http://localhost:8080/
③ 配置安全策略
创建并配置Spring Security以确保所有请求都经过Token验证:
@Configuration
@EnableWebSecurity
public class ResourceServerConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/public/**").permitAll().anyRequest().authenticated().and().oauth2ResourceServer().jwt();}
}
4、编写单点登录接口
在实现单点登录的过程中,涉及到客户端应用向认证中心请求认证并获取Token,然后将Token传递给各个微服务以进行资源访问。以下是单点登录调用代码的详细步骤,包括获取授权码、请求访问令牌以及使用令牌访问受保护资源的示例代码。
① 获取授权码
首先,客户端应用需要引导用户到SSO认证中心进行登录,并获取授权码。
 可以通过浏览器重定向实现:
@GetMapping("/login")
public void login(HttpServletResponse response) throws IOException {String authorizationUri = "http://localhost:8080/oauth/authorize";String clientId = "client-id";String redirectUri = "http://localhost:8081/callback";String responseType = "code";String scope = "read write";String authUrl = authorizationUri + "?response_type=" + responseType+ "&client_id=" + clientId+ "&redirect_uri=" + URLEncoder.encode(redirectUri, "UTF-8")+ "&scope=" + URLEncoder.encode(scope, "UTF-8");response.sendRedirect(authUrl);
}
② 获取访问令牌
用户在认证中心成功登录后,认证中心会重定向回客户端应用,并附带授权码。
 客户端应用需要使用这个授权码来请求访问令牌:
@GetMapping("/callback")
public String callback(@RequestParam("code") String code, Model model) {String tokenUri = "http://localhost:8080/oauth/token";String clientId = "client-id";String clientSecret = "client-secret";String redirectUri = "http://localhost:8081/callback";RestTemplate restTemplate = new RestTemplate();HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);headers.setBasicAuth(clientId, clientSecret);MultiValueMap<String, String> params = new LinkedMultiValueMap<>();params.add("grant_type", "authorization_code");params.add("code", code);params.add("redirect_uri", redirectUri);HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers);ResponseEntity<Map> response = restTemplate.exchange(tokenUri, HttpMethod.POST, request, Map.class);Map<String, Object> responseBody = response.getBody();String accessToken = (String) responseBody.get("access_token");model.addAttribute("accessToken", accessToken);return "home";
}
③ 使用访问令牌访问受保护资源
获取访问令牌后,客户端应用可以使用这个令牌来访问受保护的资源。
 以下是如何使用RestTemplate访问受保护资源的示例代码:
@GetMapping("/resource")
public String getResource(@RequestParam("accessToken") String accessToken, Model model) {String resourceUri = "http://localhost:8082/resource";RestTemplate restTemplate = new RestTemplate();HttpHeaders headers = new HttpHeaders();headers.setBearerAuth(accessToken);HttpEntity<String> request = new HttpEntity<>(headers);ResponseEntity<String> response = restTemplate.exchange(resourceUri, HttpMethod.GET, request, String.class);String resource = response.getBody();model.addAttribute("resource", resource);return "resource";
}
5、示例项目结构
示例项目结构如下:
/sso-auth-server├── src/main/java/com/example/auth│   ├── AuthorizationServerConfig.java│   ├── SecurityConfig.java│   └── Application.java└── src/main/resources└── application.yml/sso-gateway├── src/main/java/com/example/gateway│   └── Application.java└── src/main/resources└── application.yml/sso-user-service├── src/main/java/com/example/user│   ├── ResourceServerConfig.java│   └── Application.java└── src/main/resources└── application.yml/sso-client├── src/main/java/com/example/client│   ├── SsoController.java│   └── Application.java└── src/main/resources└── application.yml这个结构包括四个主要部分:
- 认证服务器 (sso-auth-server):负责用户认证和Token生成。
- 网关服务 (sso-gateway):负责路由请求和Token验证。
- 用户服务 (sso-user-service):作为资源服务器,提供受保护的资源。
- 客户端应用 (sso-client):负责引导用户登录、获取Token并访问受保护资源。
三、单点登录总结
1、单点登录的优势
| 优势 | 描述 | 
|---|---|
| 用户体验提升 | 用户只需一次登录即可访问所有系统,避免了重复登录的繁琐操作。 | 
| 安全性增强 | 统一的认证入口和集中式管理可以提高系统的安全性,减少各个系统独立管理认证信息的风险。 | 
| 管理简化 | 集中管理用户身份信息和认证逻辑,简化了系统的维护和管理工作。 | 
| 提高生产力 | 减少了用户在不同系统之间切换的时间,进而提升了整体工作效率。 | 
| 降低开发成本 | 开发者只需实现一次认证和授权逻辑,可以节省开发和维护多个认证系统的成本。 | 
| 统一用户管理 | 用户数据和权限集中存储和管理,使得用户信息更新和权限变更更加便捷高效。 | 
| 改善审计和合规性 | 集中的认证和授权机制有助于监控用户行为,满足法规和审计的要求。 | 
| 便于集成扩展 | 可以方便地集成新的应用系统,无需为每个新系统单独配置登录和认证流程。 | 
2、单点登录总结
单点登录(Single Sign-On, SSO)在现代分布式系统中扮演着重要角色,它不仅提高了用户体验,还增强了系统的安全性。通过Spring Cloud实现SSO,可以充分利用Spring的生态系统和强大的功能,实现高效的身份认证和授权管理。
在实际应用中,开发者应根据具体需求和系统架构选择合适的实现方案,并不断优化以提高系统性能和安全性。以下是一些关键点:
- 技术选型:选择适合业务需求的SSO实现方式,如基于OAuth2、JWT或CAS等。
- 安全策略:确保数据传输和存储的安全,采用加密技术保护用户信息,防范攻击。
- 性能优化:通过负载均衡、缓存和异步处理等技术提升系统的响应速度和稳定性。
- 用户管理:集中管理用户身份信息,确保用户数据的一致性和准确性。
- 日志和监控:实施全面的日志记录和监控机制,及时发现和处理潜在问题,确保系统的正常运行。
- 容错机制:设计健壮的容错机制,确保系统在出现故障时能够快速恢复。
通过以上措施,可以有效提升单点登录系统的整体表现,满足企业的业务需求和安全要求。

相关文章:
 
SpringCloud之SSO单点登录-基于Gateway和OAuth2的跨系统统一认证和鉴权详解
单点登录(SSO)是一种身份验证过程,允许用户通过一次登录访问多个系统。本文将深入解析单点登录的原理,并详细介绍如何在Spring Cloud环境中实现单点登录。通过具体的架构图和代码示例,我们将展示SSO的工作机制和优势&a…...
二分查找算法详讲(三种版本写法)原创
介绍: 二分查找算法(Binary Search)是一种在有序数组中查找目标元素的算法。 它的基本思想是通过将目标元素与数组的中间元素进行比较,从而将搜索范围缩小一半。 如果目标元素等于中间元素,则搜索结束;如果目标元素小…...
Git钩子(Hooks)之commit之前自动执行脚本
介绍 官方文档: 英文:https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks中文:https://git-scm.com/book/zh/v2/自定义-Git-Git-钩子 下面只复制了pre-commit部分文档,其他详见官方文档。 Git Hooks Like many other…...
 
nano机器人2:机械臂的视觉抓取
前言 参考链接: 【机械臂入门教程】机械臂视觉抓取从理论到实战 GRCNN 通过神经网络,先进行模型训练,在进行模型评估。 机械臂逆运动学求解 所有串联型6自由度机械臂均是可解的,但这种解通常只能通过数值解法得到,计算难度大&am…...
技术速递|宣布 Java on Azure 开发工具支持 Java on Azure Container Apps
作者:Jialuo Gan 排版:Alan Wang 在 Microsoft Build 2024 期间宣布,Azure Container Apps 现在可为 Java 开发人员提供丰富的操作功能。(详细内容请参见本博客)。 我们很高兴地与大家分享,Azure Toolkit for Intelli…...
 
随机森林算法实现分类
随机森林算法实现对编码后二进制数据的识别 1.直接先上代码! import numpy as np import pandas as pd from sklearn.model_selection import train_test_split, GridSearchCV from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import …...
Ubuntu卸载软件
在删除这些目录之前,你必须确定一个非常重要的事情:确认没有任何服务正在使用这些版本的 PHP。如果你删除了正在使用的 PHP 版本的扩展目录,那么依赖于这个版本的 PHP 的网站或服务可能会停止工作。 如果你确定某个版本的 PHP 没有在使用中&…...
网络工程师:网络可靠性技术
一、可靠性 平均故障间隔时间MTBF(Mean Time Between Failure)和平均修复时间MTTR(Mean Time to Repair)这两个指标来评价系统的可靠性。 1、平均故障间隔时间MTBF MTBF是指一个系统无故障运行平均时间,通常以小时为单位。MTBF越大可靠性越高。 2、平均修复时间MTTR…...
 
科技引领未来:高速公路可视化
高速公路可视化监控系统利用实时视频、传感器数据和大数据分析,通过图扑 HT 可视化展示交通流量、车速、事故和路况信息。交通管理人员可以实时监控、快速响应突发事件,并优化交通信号和指挥方案。这一系统不仅提高了道路安全性和车辆通行效率࿰…...
Golang发送POST请求并传递JSON数据
客户端 package mainimport ("c02_get_param/common""fmt""zdpgo_resty" )func main() {// Create a Resty Clientclient : zdpgo_resty.New()// 设置字符串resp, err : client.R().SetHeader("Content-Type", "application/jso…...
C++实现生产者消费者模型
生产者-消费者模型是一种典型的多线程并发模式,常用于在一个共享缓冲区中协调生产者和消费者之间的数据传递。在C中,我们可以使用标准库中的线程、互斥量和条件变量来实现该模型。以下是一个简单的生产者-消费者模型的实现示例: #include &l…...
 
【Mac】MWeb Pro(好用的markdown编辑器) v4.5.9中文版安装教程
软件介绍 MWeb Pro for Mac是一款Mac上的Markdown编辑器软件,它支持实时预览,语法高亮,自动保存和备份等功能,并且有多种主题和样式可供选择。此外,MWeb还支持多种导出格式,包括HTML、PDF、Word、ePub等&a…...
 
C++ | Leetcode C++题解之第118题杨辉三角
题目: 题解: class Solution { public:vector<vector<int>> generate(int numRows) {vector<vector<int>> ret(numRows);for (int i 0; i < numRows; i) {ret[i].resize(i 1);ret[i][0] ret[i][i] 1;for (int j 1; j &…...
 
3D透视图转的时候模型闪动怎么解决?---模大狮模型网
在3D建模与渲染的世界中,透视图是我们观察和操作模型的重要窗口。然而,有时候在旋转透视图时,模型会出现闪动的现象,这不仅影响了我们的工作效率,还可能对最终的渲染效果产生负面影响。本文将探讨这一问题的成因&#…...
 
如何创建一个vue项目?详细教程,如何创建第一个vue项目?
已经安装node.js在自己找的到的地方新建一个文件夹用于存放项目,记住文件夹的存放路径,以我为例,我的文件夹路径为D:\tydic 打开cmd命令窗口,进入刚刚的新建文件夹 切换硬盘: D: 进入文件夹:cd tydic 使…...
AWS迁移与传输之Migration Hub
AWS Migration Hub是一种集中化的迁移管理服务,可帮助企业规划、跟踪和管理在亚马逊云中进行的各种迁移活动。包括应用程序迁移、数据库迁移、服务器迁移等。 AWS Migration Hub (Migration Hub) 提供一个位置来跟踪使用多个 AWS 工具和合作伙伴解决方案的迁移任务…...
网络渗透思考
1. windows登录的明文密码,存储过程是怎么样的,密文存在哪个文件下,该文件是否可以打开,并且查看到密文 windows的明文密码:是通过LSA(Local Security Authority)进行存储加密的 存储过程:当用户输入密码之…...
 
2.8万字总结:金融核心系统数据库升级路径与场景实践
OceanBase CEO 杨冰 谈及数字化转型,如果说过去还只是头部金融机构带动效应下的“选择题”。那么现在,我相信数字化转型已经成为不论大、中、小型金融机构的“必答题”。 本文为OceanBase最新发布的《万字总结:金融核心系统数据库升级路径…...
 
Linux:进程控制(二.详细讲解进程程序替换)
上次讲了:Linux:进程地址空间、进程控制(一.进程创建、进程终止、进程等待) 文章目录 1.进程程序替换1.1概念1.2原理1.3使用一个exec 系列函数execl()函数结论与细节 2.多进程时的程序替换3.其他几个exec系…...
 
Elasticsearch8.13.4版本的Docker启动关闭HTTPS
博主环境是: 开发环境:SpringbootElasticSearch客户端对应的starter 2.6.3版本 maven配置 <!-- ElasticSearch --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elas…...
 
docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
 
智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
 
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
 
Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
 
如何应对敏捷转型中的团队阻力
应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中,明确沟通敏捷转型目的尤为关键,团队成员只有清晰理解转型背后的原因和利益,才能降低对变化的…...
 
【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅
目录 前言 操作系统与驱动程序 是什么,为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中,我们在使用电子设备时,我们所输入执行的每一条指令最终大多都会作用到硬件上,比如下载一款软件最终会下载到硬盘上&am…...
