【第17章】Spring Cloud之Gateway服务调用

文章目录

  • 前言
  • 一、用户服务
  • 二、网关服务
    • 1. 负载均衡
    • 2. 服务调用
    • 3. 登录拦截器
  • 三、单元测试
    • 1. 启动服务
    • 2. 用户不存在
    • 3. 正常登录
  • 总结


前言

在上一章我们使用JWT简单完成了用户认证,【第16章】Spring Cloud之Gateway全局过滤器(安全认证),上一章内容已经太多了,这里单独抽一章出来做个优化,前面的全局过滤器只针对登录接口的用户名密码做了简单校验,这里我们增加网关服务对用户服务的调用,参数检验完成之后我们调用用户服务的用户是否存在接口做判断,
用户存在,则继续执行登录接口,不存在则返回错误信息。


一、用户服务

package org.example.user.controller;import org.example.common.model.Result;
import org.example.common.util.JwtUtils;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** Create by zjg on 2024/7/21*/
@RestController
@RequestMapping("/user/")
public class UserController {List<String> users = List.of("admin");@RequestMapping("exist")public Boolean exist(@RequestParam("username") String username){boolean exist=false;if(users.contains(username)){exist=true;}return exist;}@RequestMapping("login")public Result<String> login(@RequestParam("username") String username, @RequestParam("password") String password){String message="用户名/密码不正确";String admin="admin";if(admin.equals(username)&&admin.equals(password)){Map<String, Object> claims=new HashMap<>();claims.put("username",username);return new Result<>(HttpStatus.OK.value(), "请求成功",JwtUtils.create(claims));}return Result.error(HttpStatus.UNAUTHORIZED.value(), message);}
}

二、网关服务

登录之前获取用户是否存在

1. 负载均衡

package org.example.gateway;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;/*** Create by zjg on 2024/7/21*/
@LoadBalancerClients({@LoadBalancerClient("user-service")
})
@EnableDiscoveryClient
@SpringBootApplication
public class GatewayApplication {public static void main(String[] args) {SpringApplication.run(GatewayApplication.class, args);}
}

2. 服务调用

package org.example.gateway.client;import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;/*** Create by zjg on 2024/7/30*/
@Service
public class UserService {@Resourceprivate WebClient.Builder webClientBuilder;public Mono<Boolean> exist(String username) {return webClientBuilder.build().get().uri("http://user-service/user/exist?username=" + username).retrieve().bodyToMono(Boolean.class);}
}

3. 登录拦截器

package org.example.gateway.filter;import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.example.common.model.Result;
import org.example.common.util.JwtUtils;
import org.example.gateway.client.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.concurrent.ExecutionException;/*** Create by zjg on 2024/7/31*/
@Component
public class LoginGlobalFilter implements GlobalFilter, Ordered {@AutowiredUserService userService;ObjectMapper objectMapper = new ObjectMapper();@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();ServerHttpResponse response = exchange.getResponse();String uri = request.getURI().getPath();if(uri.equals("/user/login")||uri.equals("/user/login/")){MultiValueMap<String, String> queryParams = request.getQueryParams();if(queryParams.containsKey("username")&&queryParams.containsKey("password")){Mono<Boolean> mono = userService.exist(queryParams.getFirst("username"));try {Boolean exist = mono.doOnSuccess((e)->{}).toFuture().get();if (Boolean.FALSE.equals(exist)) {response.setStatusCode(HttpStatus.BAD_REQUEST);Result result = Result.error(HttpStatus.BAD_REQUEST.value(), "登录失败", "用户名不存在!");return write(response, result);}} catch (InterruptedException e) {throw new RuntimeException(e);} catch (ExecutionException e) {throw new RuntimeException(e);}return chain.filter(exchange);}else {response.setStatusCode(HttpStatus.BAD_REQUEST);Result result = Result.error(HttpStatus.BAD_REQUEST.value(), "登录失败", "用户名和密码不能为空!");return write(response,result);}}HttpHeaders headers = request.getHeaders();String authorization = headers.getFirst("Authorization");if(Boolean.FALSE.equals(StringUtils.hasText(authorization))||Boolean.FALSE.equals(JwtUtils.verify(authorization.startsWith("Bearer")?authorization.substring(authorization.indexOf("Bearer")+7):authorization))){response.setStatusCode(HttpStatus.UNAUTHORIZED);Result result = Result.error(HttpStatus.UNAUTHORIZED.value(), "认证失败", "token验证失败,请重新获取token后重试!");return write(response,result);}request = exchange.getRequest().mutate().headers(httpHeaders -> httpHeaders.add("Source-Mark", "Z2F0ZXdheQ==")).build();return chain.filter(exchange.mutate().request(request).build());}public Mono<Void> write(ServerHttpResponse response, Result result) {try {response.getHeaders().setContentType(MediaType.APPLICATION_JSON);return response.writeWith(Flux.just(response.bufferFactory().wrap(objectMapper.writeValueAsBytes(result))));} catch (JsonProcessingException e) {return response.setComplete();}}@Overridepublic int getOrder() {return -1;}
}

三、单元测试

1. 启动服务

在这里插入图片描述

2. 用户不存在

在这里插入图片描述

3. 正常登录

在这里插入图片描述


总结

回到顶部

到这里我们就完成了在网关服务中对其他服务的调用和处理,不要走开,后面的内容更精彩!!!

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

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

相关文章

端点区间影响

前言&#xff1a;这一题本来想就是直接来一个前缀和来写&#xff0c;直接左边加一&#xff0c;右边减一&#xff0c;但是细想好像有问题&#xff0c;我们平时做的题目左边端点造成的影响会对这一段区间造成影响&#xff0c;但是这一题的话超过了左边端点就不会有影响了 那这一题…

vue3-ts:husky + prettier / 代码格式化工具

一、Prettier简介 Prettier是一个流行的代码格式化工具&#xff0c;它的主要作用是帮助开发者自动规范化代码的格式&#xff0c;提高代码的可读性和一致性。Prettier通过解析代码并使用自己的规则重新打印它&#xff0c;以确保代码风格的一致性和符合预设的格式化标准。 二、…

WPF学习(8)- Button按钮

1. 用法解析 Button因为继承了ButtonBase&#xff0c;而ButtonBase又继承了ContentControl&#xff0c;所以&#xff0c;Button可以通过设置Content属性来设置要显示的内容。例如 <Button Content"确定"/>我们使用Button的时机&#xff0c;通常是鼠标点击事件…

【Dash】使用 dash_mantine_components 创建图表

一、Styling Your App The examples in the previous section used Dash HTML Components to build a simple app layout, but you can style your app to look more professional. This section will give a brief overview of the multiple tools that you can use to enhan…

树莓派5进行YOLOv8部署的4种不同部署方式检测速度对比:pytorch、onnx、ncnn、tflite

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

Python 异步编程:Asyncio 实现原理

常见的并发模型 多进程/多线程异步ActorPub/Sub Python 异步的基石&#xff1a;协程 协程简介 概念&#xff1a;协作式多任务的子程序&#xff0c;用户态线程或微线程&#xff08;Coroutine&#xff09;。 特点&#xff1a;子程序执行可以中断&#xff0c;恢复后不会丢失之…

生物反应器对Organoids培养有啥帮助?有几种?快来看看!

Bioreactor Technologies for Enhanced Organoid Culture是《INTERNATIONAL JOURNAL OF MOLECULAR SCIENCES》上的一篇文章&#xff0c;介绍了用于类器官培养的生物反应器&#xff0c;包括搅拌式、微流体、旋转壁容器和电刺激四类。搅拌式生物反应器通过改善氧合和实现适当的谱…

【iOS多线程(二)】GCD其他方法详解

GCD其他方法 dispatch_semaphore &#xff08;信号量&#xff09;什么是dispatch_semaphore(信号量)?dispatch_semaphore主要的三个方法dispatch_semaphore主要作用线程安全线程同步 dispatch_afterdispatch_time_t 两种形式 GCD 一次性代码&#xff08;只执行一次&#xff09…

面向 RAG 应用开发者的实用指南和建议

向量搜索并非轻而易举&#xff01; 向量搜索&#xff0c;也称为向量相似性搜索或最近邻搜索&#xff0c;是一种常见于 RAG 应用和信息检索系统中的数据检索技术&#xff0c;用于查找与给定查询向量相似或密切相关的数据。业内通常会宣传该技术在处理大型数据集时非常直观且简单…

【C语言】C语言期末突击/考研--结构体与C++引用

一、结构体--结构体对齐--结构体数组 1.1.结构体的定义、初始化、结构体数组 有时候需要将不同类型的数据组合为一一个整体&#xff0c;以便于引用。 例如&#xff0c;一名学生有学号、姓 名、性别、年龄、地址等属性&#xff0c;如果针对学生的学号、姓名、年龄等都单独定义一…

【MYSQL】表操作

目录 查看当前数据库含有表查看表结构创建表插入&#xff08;新增create&#xff09;查询&#xff08;retrieve&#xff09;全列查询指定列查询查询列是表达式别名查询(as)去重查询(distinct)排序查询(order by)条件查询(where)比较/逻辑运算符使用 分页查询(limit) 一条语句各…

【若依项目-RuoYi】掌握若依前端的基本流程

搞毕设项目&#xff0c;使用前后端分离技术&#xff0c;后端springBoot&#xff0c;前端vue3element plus。自己已经写好前端与后端代码&#xff0c;但想换一个前端界面所以使用到了若依&#xff0c;前前后后遇到许多坑&#xff0c;记录一下&#xff0c;方便之后能够快速回忆。…

尚硅谷谷粒商城项目笔记——八、安装node.js【电脑CPU:AMD】

八、安装node.js 注&#xff1a; [!NOTE] 查看本机系统 官网选择node.js版本 1傻瓜式安装&#xff0c;注意选择路径 图一 图二 至此&#xff0c;nodejs安装完成&#xff01; 2环境配置 找到安装nodejs的路径新增 node_global 和node_cache文件夹 创建完两个空文件夹&#x…

如何快速入门 PyTorch ?

PyTorch是一个机器学习框架&#xff0c;主要依靠深度神经网络&#xff0c;目前已迅速成为机器学习领域中最可靠的框架之一。 PyTorch 的大部分基础代码源于 Ronan Collobert 等人 在 2007 年发起的 Torch7 项目&#xff0c;该项目源于 Yann LeCun 和 Leon Bottou 首创的编程语…

0207、创建场景状态的三个子类

VS使用的是3.5框架&#xff0c;会自带Linq这一行&#xff0c;Unity不支持&#xff0c;需要删除 一、创建三个场景 二、创建三个子类

本科阶段最后一次竞赛Vlog——2024年智能车大赛智慧医疗组准备全过程——5Webscoket节点的使用

本科阶段最后一次竞赛Vlog——2024年智能车大赛智慧医疗组准备全过程——5Webscoket节点的使用 ​ 有了前面几篇文章的铺垫&#xff0c;现在已经可以实现我到手测试那一步的 1.解读usb_websocket_display.launch.py ​ 首先进入这个目录/root/dev_ws/src/origincar/originca…

Java语言程序设计——篇十二

&#x1f33f;&#x1f33f;&#x1f33f;跟随博主脚步&#xff0c;从这里开始→博主主页&#x1f33f;&#x1f33f;&#x1f33f; 欢迎大家&#xff1a;这里是我的学习笔记、总结知识的地方&#xff0c;喜欢的话请三连&#xff0c;有问题可以私信&#x1f333;&#x1f333;&…

ChatGPT能代替网络作家吗?

最强AI视频生成&#xff1a;小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频百万播放量https://aitools.jurilu.com/ 当然可以&#xff01;只要你玩写作AI玩得6&#xff0c;甚至可以达到某些大神的水平&#xff01; 看看大神、小白、AI输出内容的区…

【枚举 图论】2242. 节点序列的最大得分

本文涉及知识点 枚举 图论知识汇总 LeetCode 2242. 节点序列的最大得分 给你一个 n 个节点的 无向图 &#xff0c;节点编号为 0 到 n - 1 。 给你一个下标从 0 开始的整数数组 scores &#xff0c;其中 scores[i] 是第 i 个节点的分数。同时给你一个二维整数数组 edges &…