SpringCloud之SSO单点登录-基于Gateway和OAuth2的跨系统统一认证和鉴权详解

news2024/11/18 15:46:31

单点登录(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 {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public 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");
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager)
                 .tokenStore(new InMemoryTokenStore());
    }
}
③ 配置Spring Security

创建并配置Spring Security:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("user")
            .password("{noop}password")
            .roles("USER");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .anyRequest().authenticated()
            .and()
            .formLogin().permitAll();
    }

    @Bean
    @Override
    public 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-service
          uri: lb://USER-SERVICE
          predicates:
            - Path=/user/**
          filters:
            - TokenRelay
  security:
    oauth2:
      client:
        provider:
          custom:
            authorization-uri: http://localhost:8080/oauth/authorize
            token-uri: http://localhost:8080/oauth/token
            user-info-uri: http://localhost:8080/userinfo
            jwk-set-uri: http://localhost:8080/.well-known/jwks.json
        registration:
          custom:
            client-id: client-id
            client-secret: client-secret
            authorization-grant-type: authorization_code
            redirect-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 {

    @Override
    protected 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等。
  • 安全策略:确保数据传输和存储的安全,采用加密技术保护用户信息,防范攻击。
  • 性能优化:通过负载均衡、缓存和异步处理等技术提升系统的响应速度和稳定性。
  • 用户管理:集中管理用户身份信息,确保用户数据的一致性和准确性。
  • 日志和监控:实施全面的日志记录和监控机制,及时发现和处理潜在问题,确保系统的正常运行。
  • 容错机制:设计健壮的容错机制,确保系统在出现故障时能够快速恢复。

通过以上措施,可以有效提升单点登录系统的整体表现,满足企业的业务需求和安全要求。

在这里插入图片描述

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

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

相关文章

mysql 8 [HY000][1114] The table ‘/tmp/#sql4c3_3e5a0_2‘ is full

分组有个比较大的表&#xff0c;出现了临时表空间满了的情况&#xff1b; 试用该sql 语句&#xff1a; SHOW GLOBAL VARIABLES LIKE internal_tmp_mem_storage_engine; 可以看到 默认临时结果是用临时表存的&#xff0c;在mysql的my.cnt可以改临时空间的大小 但是磁盘哪有内…

2、python环境的安装-mac系统下

打开官网&#xff0c;downloads下边有macOS&#xff0c;点击&#xff1a; 选择最新版本&#xff0c;点击&#xff0c;进入下边的页面&#xff0c;一直往下滑&#xff0c;看到files中有个macOS的版本&#xff0c;点击下载 点击下载后是pkg的安装包&#xff0c;点击安装。 一步步…

浙江大学数据结构MOOC-课后习题-第九讲-排序3 Insertion or Heap Sort

题目汇总 浙江大学数据结构MOOC-课后习题-拼题A-代码分享-2024 题目描述 测试点 思路分析 和上一题的思路一样&#xff0c;每进行一次迭代&#xff0c;来验证当前序列是否和给定的序列相同 代码展示 #include <cstdlib> #include <iostream> #define MAXSIZE 10…

代码随想录算法训练营第七天| 454.四数相加II 、383. 赎金信、 15. 三数之和、18. 四数之和

454.四数相加II 题目链接&#xff1a; 454.四数相加II 文档讲解&#xff1a;代码随想录 状态&#xff1a;没做出来&#xff0c;没想到考虑重复的情况&#xff01; 题解&#xff1a; public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {// 结果计数…

100个 Unity小游戏系列三 -Unity 抽奖游戏专题一 转盘抽奖游戏

一 、效果展示 二、知识点 2.1 布局需要实现功能 1、转动的根目录为itemSpinRoot 2、创建对应的item 3、每个item转动的角度 2.2 代码 public class WheelDialog : UIBase{[SerializeField] Button btnClick;[SerializeField] Button btnClose;[SerializeField] Sprite[] ite…

【错误记录】HarmonyOS 运行报错 ( Failure INSTALL _PARSE _FAILED _USESDK _ERROR )

文章目录 一、报错信息二、问题分析三、解决方案 一、报错信息 在 DevEco Studio 中 , 使用 远程设备 , 向 P40 Failure[INSTALL_PARSE_FAILED_USESDK_ERROR] compileSdkVersion and releaseType of the app do not match the apiVersion and releaseType on the device. 二、…

【蓝桥杯】第十四届蓝桥杯大赛软件赛国赛C/C++ 大学 B 组

答题结果页 - 蓝桥云课 (lanqiao.cn) 0子2023 - 蓝桥云课 (lanqiao.cn)&#xff08;暴力枚举 #include<bits/stdc.h> using lllong long; using ullunsigned long long; #define fir first #define sec second //#define int llconst int N1e510; const int mod1e97;int…

使用prometheus监测MySQL主从同步状态方案

说明&#xff1a;本文介绍如何使用prometheus、alertmanager监测MySQL主从&#xff0c;当从节点中断同步时&#xff0c;发送邮箱报警&#xff0c;并使用grafana将数据视图化。 结构图如下&#xff1a; 安装 &#xff08;1&#xff09;安装应用 首先&#xff0c;来安装promet…

谷歌推出TransformerFAM架构,以更低的消耗处理长序列文本

Transformer对大模型界的影响力不言而喻&#xff0c;ChatGPT、Sora、Stable Difusion等知名模型皆使用了该架构。 但有一个很明显的缺点&#xff0c;其注意力复杂度的二次方增长在处理书籍、PDF等超长文档时会显著增加算力负担。 虽然会通过滑动窗口注意力和稀疏注意力等技术…

全栈实现图片验证码及知识补充 全栈开发之路——全栈篇(4)

全栈开发一条龙——前端篇 第一篇&#xff1a;框架确定、ide设置与项目创建 第二篇&#xff1a;介绍项目文件意义、组件结构与导入以及setup的引入。 第三篇&#xff1a;setup语法&#xff0c;设置响应式数据。 第四篇&#xff1a;数据绑定、计算属性和watch监视 第五篇 : 组件…

100个 Unity小游戏系列六 -Unity 抽奖游戏专题四 翻卡游戏

一、演示效果 二、知识点讲解 2.1 布局 void CreateItems(){reward_data_list reward_data_list ?? new List<RewardData>();reward_data_list.Clear();for (int i 0; i < ItemCount; i){GameObject item;if (i 1 < itemParent.childCount){item itemParent…

AI革命:生活无处不智能

AI革命&#xff1a;生活无处不智能 &#x1f604;生命不息&#xff0c;写作不止 &#x1f525; 继续踏上学习之路&#xff0c;学之分享笔记 &#x1f44a; 总有一天我也能像各位大佬一样 &#x1f3c6; 博客首页 怒放吧德德 To记录领地 &#x1f31d;分享学习心得&#xff0…

PyBullet 物理引擎

PyBullet是一个开源的物理仿真库&#xff0c;基于Bullet Physics SDK这一成熟的、广泛使用的开源物理引擎。它提供了Python接口&#xff0c;使开发者能够利用Bullet强大的物理仿真能力&#xff0c;同时享受Python的易用性。PyBullet支持多种物理学模型&#xff0c;如刚体、骨骼…

CTF流量分析之wireshark使用

01.基本介绍 在CTF比赛中&#xff0c;对于流量包的分析取证是一种十分重要的题型。通常这类题目都是会提供一个包含流量数据的pcap文件&#xff0c;参赛选手通过该文件筛选和过滤其中无关的流量信息&#xff0c;根据关键流量信息找出flag或者相关线索。 pcap流量包的分析通常…

在 GPT-4o 释放完整能力前,听听实时多模态 AI 创业者的一手经验 | 编码人声

「编码人声」是由「RTE开发者社区」策划的一档播客节目&#xff0c;关注行业发展变革、开发者职涯发展、技术突破以及创业创新&#xff0c;由开发者来分享开发者眼中的工作与生活。 5 月中旬 GPT-4o 的发布&#xff0c;让人与 AI 的交互&#xff0c;从对话框的文本交流加速推进…

【C语言深度解剖】(14):结构体内存对齐(详细配图讲解)

&#x1f921;博客主页&#xff1a;醉竺 &#x1f970;本文专栏&#xff1a;《C语言深度解剖》 &#x1f63b;欢迎关注&#xff1a;感谢大家的点赞评论关注&#xff0c;祝您学有所成&#xff01; ✨✨&#x1f49c;&#x1f49b;想要学习更多C语言深度解剖点击专栏链接查看&…

【网络层】ICMP 因特网控制协议

文章目录 ICMP 含义以及作用ICMP协议解析结合ICMP协议和ping常见问题 ICMP 含义以及作用 ICMP&#xff1a;Internet control massage protocol 因特网控制协议 Internet控制报文协议ICMP是网络层的一个重要协议。 ICMP协议用来在网络设备间传递各种差错和控制信息&#xff0c;…

QA测试开发工程师面试题满分问答25: JVM瓶颈分析,举例说明

回答思路 JVM 性能瓶颈概述: JVM (Java Virtual Machine)是 Java 程序运行的基础环境,其性能直接影响到应用程序的整体性能。在实际项目中,我们经常会遇到 JVM 性能瓶颈,导致应用程序出现响应缓慢、CPU 利用率高、内存溢出等问题。因此,分析和诊断 JVM 瓶颈是非常重要的工作,有…

谷歌插件编写

目录 manifest.json {"manifest_version": 3,"name": "Floating Ball","version": "1.0","description": "A floating ball on the right side of the webpage.","permissions": ["act…

XS2185一款八通道以太网供电控制器

XS2185是一款八通道以太网供电控制器。 XS2185通过侦测各通道的DET管脚输入电压 来判断是否有合格的负载/PD接入系统&#xff0c;以决定 是否开启MOS供电开关。 当通道已经处于供电状态时&#xff0c;XS2185通过侦 测SENSE管脚的输入电压&#xff0c;以判断供电是否发生 …