【Sa-Token|4】Sa-Token微服务项目应用

若微服务数量多,如果每个服务都改动,工作量大,则可以只在网关和用户中心进行改动,也是可以实现单点登录的。
这种方式可以通过在网关服务中生成和验证 Sa-Token,并将其与现有的 Token关联存储在 Redis 中。用户中心提供额外的接口来验证和生成新的 Sa-Token。
这样只需要改造网关和用户服务,其他服务保持现状,即可实现单点登录

在这里插入图片描述

实现方案

为了实现单点登录 (SSO)的目标,同时尽量减少对现有系统的改动,可以在网关和用户中心进行必要的改动,以确保用户在登录后能够在多个系统中无缝访问。

下面是详细的方案和步骤:

一、用户中心改造

用户中心需要提供两个接口:

  1. 登录接口:用户登录并生成原有业务系统的 Token。
  2. Token 验证和 Sa-Token 生成接口:验证原有 Token 并生成 Sa-Token。
1. 登录接口
@RestController
@RequestMapping("/auth")
public class AuthController {@PostMapping("/login")public ResponseEntity<Map<String, Object>> login(@RequestParam String username, @RequestParam String password) {Map<String, Object> result = new HashMap<>();// 进行用户名和密码校验if (checkCredentials(username, password)) {String originalToken = generateOriginalToken(username); // 生成原有业务系统的 Tokenresult.put("originalToken", originalToken);return ResponseEntity.ok(result);}result.put("error", "登录失败");return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(result);}private boolean checkCredentials(String username, String password) {// 检查用户名和密码逻辑return true; // 假设校验成功}private String generateOriginalToken(String username) {// 生成原有业务系统的 Tokenreturn "original-token";}
}
2. Token 验证和 Sa-Token 生成接口
@RestController
@RequestMapping("/auth")
public class AuthController {@Autowiredprivate RedisTemplate<String, String> redisTemplate;@GetMapping("/check")public ResponseEntity<SaResult> checkToken(@RequestParam String token) {// 验证原有 Tokenif (validateOriginalToken(token)) {String userId = getUserIdFromOriginalToken(token);StpUtil.login(userId);String saToken = StpUtil.getTokenValue();// 存储原有 Token 和 Sa-Token 的映射关系redisTemplate.opsForValue().set("sa-token:" + token, saToken);redisTemplate.opsForValue().set("original-token:" + saToken, token);return ResponseEntity.ok(SaResult.ok("Token 有效").set("saToken", saToken));}return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(SaResult.error("Token 无效"));}private boolean validateOriginalToken(String token) {// 验证原有业务系统的 Tokenreturn true; // 假设校验成功}private String getUserIdFromOriginalToken(String token) {// 从原有业务系统的 Token 中解析出用户IDreturn "parsed-user-id";}
}

二、网关服务改造

网关服务需要在所有请求到达后端服务前,进行原有 Token 的验证和 Sa-Token 的生成和验证。

1. 引入 Redis 依赖

确保网关服务的 pom.xml 文件中包含 Redis 依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2. 配置 Redis

application.yml 文件中配置 Redis 连接信息:

spring:redis:host: localhostport: 6379password: ""
3. 网关服务 Token 校验过滤器
@Component
public class TokenFilter implements GlobalFilter, Ordered {@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate RedisTemplate<String, String> redisTemplate;@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {String originalToken = exchange.getRequest().getHeaders().getFirst("Authorization");if (originalToken != null) {String saToken = redisTemplate.opsForValue().get("sa-token:" + originalToken);if (saToken == null) {// 调用用户中心的接口生成 Sa-TokensaToken = generateSaToken(originalToken);if (saToken == null) {exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);return exchange.getResponse().setComplete();}}exchange.getRequest().mutate().header("Sa-Token", saToken).build();return chain.filter(exchange);}exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);return exchange.getResponse().setComplete();}private String generateSaToken(String originalToken) {// 调用用户中心的接口生成 Sa-TokenString url = "http://user-center/auth/check?token=" + originalToken;ResponseEntity<SaResult> response = restTemplate.getForEntity(url, SaResult.class);if (response.getStatusCode() == HttpStatus.OK && response.getBody().getCode() == 200) {return response.getBody().get("saToken").toString();}return null;}@Overridepublic int getOrder() {return -100;}
}

三、工作流程

  1. 用户登录

    • 用户通过用户中心的登录接口进行登录,用户中心生成原有业务系统的 Token 并返回给前端。
  2. 请求网关

    • 前端在请求其他服务时,将原有的 Token 添加到请求头中,发送请求到网关。
  3. 网关处理

    • 网关拦截请求,从请求头中获取原有的 Token。
    • 网关调用用户中心的 Token 验证接口来验证原有 Token 并生成 Sa-Token。
    • 将原有 Token 和 Sa-Token 的映射关系存储在 Redis 中。
    • 将 Sa-Token 添加到请求头中,转发请求到后端服务。
  4. 后端服务

    • 后端服务可以继续保持现有的 Token 逻辑,不需要改动。所有的 Token 验证和生成逻辑都在网关和用户中心处理。

模块详细介绍

在上述方案中,实现单点登录的关键步骤包括:

  1. 用户中心提供接口验证原有 Token 并生成 Sa-Token:通过 /auth/check 接口,用户中心接收原有业务系统的 Token,验证其有效性并生成新的 Sa-Token。
  2. 网关服务拦截所有请求,验证和生成 Sa-Token:网关服务在接收到请求时,首先检查请求头中的原有 Token,并调用用户中心的 /auth/check 接口来验证 Token 并生成 Sa-Token,将生成的 Sa-Token 存储在 Redis 中,并添加到请求头中转发给后端服务。

这些步骤确保了用户在登录后,可以使用原有 Token 进行验证,并通过 Sa-Token 进行单点登录的验证,从而实现了单点登录的效果。

具体的单点登录实现过程

  1. 用户登录生成原有业务系统的 Token

    • 用户通过用户中心的登录接口进行登录。
    • 用户中心生成原有业务系统的 Token 并返回给前端。
  2. 网关服务处理用户请求

    • 前端在请求其他服务时,将原有的 Token 添加到请求头中,发送请求到网关。
    • 网关服务拦截请求,获取请求头中的原有 Token。
  3. 网关服务验证和生成 Sa-Token

    • 网关服务调用用户中心的 /auth/check 接口,验证原有 Token 的有效性。
    • 用户中心验证原有 Token 有效后,生成 Sa-Token 并返回给网关服务。
    • 网关服务将原有 Token 和 Sa-Token 的映射关系存储在 Redis 中。
    • 网关服务将生成的 Sa-Token 添加到请求头中,转发请求到后端服务。
  4. 后端服务处理请求

    • 后端服务可以继续保持现有的 Token 验证逻辑,不需要改动。
    • 所有的 Token 验证和生成逻辑都在网关和用户中心处理。

实现细节

1. 用户中心新增 Token 验证和生成 Sa-Token 接口
@RestController
@RequestMapping("/auth")
public class AuthController {@Autowiredprivate RedisTemplate<String, String> redisTemplate;@GetMapping("/check")public ResponseEntity<SaResult> checkToken(@RequestParam String token) {// 验证原有 Tokenif (validateOriginalToken(token)) {String userId = getUserIdFromOriginalToken(token);StpUtil.login(userId);String saToken = StpUtil.getTokenValue();// 存储原有 Token 和 Sa-Token 的映射关系redisTemplate.opsForValue().set("sa-token:" + token, saToken);redisTemplate.opsForValue().set("original-token:" + saToken, token);return ResponseEntity.ok(SaResult.ok("Token 有效").set("saToken", saToken));}return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(SaResult.error("Token 无效"));}private boolean validateOriginalToken(String token) {// 验证原有业务系统的 Tokenreturn true; // 假设校验成功}private String getUserIdFromOriginalToken(String token) {// 从原有业务系统的 Token 中解析出用户IDreturn "parsed-user-id";}
}
2. 网关服务 Token 校验过滤器
@Component
public class TokenFilter implements GlobalFilter, Ordered {@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate RedisTemplate<String, String> redisTemplate;@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {String originalToken = exchange.getRequest().getHeaders().getFirst("Authorization");if (originalToken != null) {String saToken = redisTemplate.opsForValue().get("sa-token:" + originalToken);if (saToken == null) {// 调用用户中心的接口生成 Sa-TokensaToken = generateSaToken(originalToken);if (saToken == null) {exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);return exchange.getResponse().setComplete();}}exchange.getRequest().mutate().header("Sa-Token", saToken).build();return chain.filter(exchange);}exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);return exchange.getResponse().setComplete();}private String generateSaToken(String originalToken) {// 调用用户中心的接口生成 Sa-TokenString url = "http://user-center/auth/check?token=" + originalToken;ResponseEntity<SaResult> response = restTemplate.getForEntity(url, SaResult.class);if (response.getStatusCode() == HttpStatus.OK && response.getBody().getCode() == 200) {return response.getBody().get("saToken").toString();}return null;}@Overridepublic int getOrder() {return -100;}
}

工作流程总结

  1. 用户登录并获取原有业务系统的 Token。
  2. 用户在请求服务时,携带原有 Token 发送请求到网关。
  3. 网关验证原有 Token,并通过用户中心生成 Sa-Token。
  4. 网关将 Sa-Token 存储在 Redis 中,并添加到请求头中转发给后端服务。
  5. 后端服务保持现有逻辑不变,网关和用户中心负责所有的 Token 验证和生成。

通过以上步骤,达成了在现有系统中实现单点登录的目标,同时最大限度地减少了对现有系统的改动。

五、总结

通过上述详细的改造步骤和代码示例,可以在不改动后端服务的情况下,实现单点登录。所有的 Token
验证和生成逻辑都集中在网关和用户中心,实现了 Token 的统一管理和验证。这样既实现了单点登录的目标,又最大限度地减少了对现有系统的改造。

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

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

相关文章

自学鸿蒙HarmonyOS的ArkTS语言<三>路由跳转及传参

【官方文档传送门】 一、导入模块 import router from ohos.router二、新增页面配置 三、常用api 1、跳转到应用内的指定页面 build() {Row() {Button(下一页).onClick(() > {router.pushUrl({url: pages/Index2,params: {name: test}})})}.height(100%)}2、用应用内的某…

【Java】已解决java.net.UnknownHostException异常

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决java.net.UnknownHostException异常 在Java的网络编程中&#xff0c;java.net.UnknownHostException是一个常见的异常&#xff0c;它通常表明在尝试解析主机名时出现了问题。…

php基础语法_面向对象

PHP php代码标记 多种标记来区分php脚本 ASP标记&#xff1a;<% php代码 %> 短标记&#xff1a; 脚本标记: 标准标记&#xff08;常用&#xff09;&#xff1a; 简写风格&#xff1a; ASP风格&#xff1a;<% php代码 %> 注意&#xff1a;简写风格和ASP风格…

myslql事务示例

在 MySQL 中&#xff0c;事务&#xff08;Transaction&#xff09;是一组要么全部执行&#xff0c;要么全部不执行的SQL语句。这可以确保数据的一致性和完整性。事务管理的核心包括四个属性&#xff0c;即原子性&#xff08;Atomicity&#xff09;、一致性&#xff08;Consiste…

RegionClip环境安装踩坑指南

RegionClip环境安装 RegionClip环境安装)问题1问题2问题3问题4问题5 RegionClip环境安装) 特别强调&#xff0c;不要单独去安装detectron2&#xff0c;会出现model.clip不存在的错误&#xff0c;通过python -m pip install -e RegionCLIP就可以问题1 问题&#xff1a;torch-c…

安卓SDK发布到maven

【参考文档】 maven central:https://vanniktech.github.io/gradle-maven-publish-plugin/central/#in-memory-gpg-key 安装gpg&#xff1a; https://central.sonatype.org/publish/requirements/gpg/#publish-or-drop-the-deployment 【流程】 1、进入Maven Central: P…

sourceTree 解决remote: HTTP Basic: Access denied报错mac

解决sourceTree中remote: HTTP Basic: Access denied报错 mac sourcetree报错报错原因解决方案 mac sourcetree报错 warning: invalid credential line: xxx.com remote: HTTP Basic: Access denied fatal参考链接&#xff1a;https://developer.aliyun.com/article/1304149 …

在分数限制下,是选择好专业还是好学校取决于你个人的兴趣、职业规划和实际情况。

分数限制下&#xff0c;选好专业还是选好学校&#xff1f; 方向一&#xff1a;专业解析 选择专业与选择学校之间的决策确实是一个复杂的过程&#xff0c;涉及到个人兴趣、职业目标以及教育资源等多个因素。我来结合实际场景&#xff0c;探讨不同专业的优势、未来挑战以及专业与…

高效学习方法笔记

part1.学习方法: 1.知识多不等于学习能力强&#xff1b; 2.考试是最有效的学习策略&#xff1b; 3.间隔练习使知识存储更牢固&#xff1b; 4.自我检索&#xff08;反思&#xff09;能更好的掌握知识&#xff1b; 5.穿插练习有助于长期记忆&#xff1b; 6.多样性练习促进知识的…

ruoyi登录功能源码分析

Ruoyi登录功能源码分析 上一篇文章我们分析了一下若依登录验证码生成的代码&#xff0c;今天我们来分析一下登录功能的代码 1、发送登录请求 前端通过http://localhost/dev-api/login向后端发送登录请求并携带用户的登录表单 在后端中的com.ruoyi.web.controller.system包下…

mysql中使用json_arrayagg(),指定数组中元素排序

背景&#xff1a; 按照某个字段分组&#xff0c;分组后将同类型的元素聚合在一个数组中&#xff0c;最后再比较数组是否相等。 使用json_arrayagg()&#xff0c;数组中元素排序为数据所属表的默认排序&#xff0c;不满足比较数组是否相等的需求。 既然要排序&#xff0c;于是写…

14-Kafka-Day03

第 5 章 Kafka 消费者 5.1 Kafka 消费方式 5.2 Kafka 消费者工作流程 5.2.1 消费者总体工作流程 一个消费者组中的多个消费者&#xff0c;可以看作一个整体&#xff0c;一个组内的多个消费者是不可能去消费同一个分区的数据的&#xff0c;要不然就消费重复了。 5.2.2 消费者…

WIC 图像处理初体验——读取像素的值

先放上运行结果&#xff1a; 可以发现红绿蓝是从后往前的。 必须以C方式编译代码&#xff01; #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <wincodec.h>int main(void) {CoInitialize(nullptr);IWICImagingFactory* fac;CoCreateInstance(CLS…

勒索病毒猖狂,请提前做好安全防护,德迅卫士保护你的安全

随着互联网的飞速发展&#xff0c;网络安全问题日益凸显。其中&#xff0c;勒索病毒作为一种极具危害性的网络安全威胁&#xff0c;已经引起了广泛关注。为了帮助大家更好地预防和应对勒索病毒攻击&#xff0c;我们特地为您精心准备了这份超实用的勒索病毒自救预防指南。让我们…

数据中心技术:大数据时代的机遇与挑战

在大数据时代&#xff0c;数据中心网络对于存储和处理大量信息至关重要。随着云计算的出现&#xff0c;数据中心已成为现代技术的支柱&#xff0c;支持社交媒体、金融服务等众多行业。然而&#xff0c;生成和处理的大量数据带来了一些挑战&#xff0c;需要创新的解决方案。在这…

Android系统 抓trace方法(手机及车机)

1、先说说什么是trace trace是一种以perfetto.trace结尾的文件。一般用来分析卡顿、启动时间慢等问题&#xff0c;还可以用来分析方法耗时&#xff0c;android系统的性能、功耗等等问题。所需要使用到的网站是&#xff1a; Perfetto UI 他的前身是Systrace&#xff0c;不过Pe…

分布式事务的八种方案解析

分布式事务的八种方案解析 针对不同的分布式场景业界常见的解决方案有2PC、TCC、可靠消息最终一致性、最大努力通知等方案&#xff0c;以下总结8 种常见的解决方案&#xff0c;帮助大家在实际的分布式系统中更好地运用事务。 1.2PC 二阶段提交协议&#xff08;Two-phase commit…

2024年旅游与经济发展国际会议(ICTED 2024)

2024年旅游与经济发展国际会议&#xff08;ICTED 2024&#xff09; 2024 International Conference on Tourism and Economic Development 【重要信息】 大会地点&#xff1a;青岛 大会官网&#xff1a;http://www.icicted.com 投稿邮箱&#xff1a;icictedsub-conf.com 【注意…

第一个Java程序

编写第一个Java程序通常从经典的"Hello,World!"程序开始。下面是一个简单的Java程序示例&#xff0c;它将打印出"Hello, World!"到控制台&#xff1a; 1.编写代码&#xff1a; 打开文本编辑器&#xff08;如记事本、Notepad、Visual StudioCode等&#x…

Oracle 学习之 各种语句

概览 Oracle 学习之 DDL 语句Oracle 学习之 DCL 语句Oracle 学习之 DML 语句Oracle 学习之 DTL 语句