概述
要在每个微服务中获取用户信息,可以采用以下几种方法:
1.通过认证和授权:在用户登录时,进行身份认证并生成访问令牌(token)。将该令牌与用户相关的信息存储在安全的方式下,比如使用JWT(JSON Web Token)等。在每个微服务中,对请求进行校验,验证令牌的有效性,并解析出用户信息。
2.使用网关或API管理工具:通过引入网关或API管理工具,所有请求都经过该组件进行路由和处理。在网关中,可以将用户信息添加到请求头部或者设置上下文变量,在微服务中可以方便地从请求中提取用户信息。
至于在微服务之间传递用户信息,可以考虑以下方式:
1.使用请求头部:在每个微服务之间传递请求时,可以将用户信息添加到请求头部,在接收端微服务中解析请求头部获取用户信息。
2.使用消息队列:使用消息队列作为微服务之间的通信机制,当一个微服务需要将用户信息传递给另一个微服务时,可以将用户信息封装成消息发送给消息队列,接收端微服务从消息队列中获取用户信息。
3.使用分布式缓存:将用户信息存储到分布式缓存中,比如Redis等,每个微服务可以从缓存中获取用户信息。
需要注意的是,为了确保用户信息的安全性和隐私保护,需要采取适当的安全措施,比如使用加密算法对用户信息进行加密处理,在跨网络传输时采用HTTPS等安全通信协议,以及权限控制等。同时,合理设计微服务架构,避免过度依赖和传递大量的用户信息,以减少潜在的风险。
由于每个微服务都有不同的地址或端口,入口不同,相信大家在与前端联调的时候发现了一些问题:
- 请求不同数据时要访问不同的入口,需要维护多个入口地址,麻烦
- 前端无法调用nacos,无法实时更新服务列表
单体架构时我们只需要完成一次用户登录、身份校验,就可以在所有业务中获取到用户信息。而微服务拆分后,每个微服务都独立部署,这就存在一些问题:
不要着急,这些问题都可以在今天的学习中找到答案,我们会通过网关技术解决上述问题。今天的内容会分为3章:
- 第一章:网关路由,解决前端请求入口的问题。
- 第二章:网关鉴权,解决统一登录校验和用户信息获取的问题。
- 第三章:统一配置管理,解决微服务的配置文件重复和配置热更新问题。
通过今天的学习你将掌握下列能力:
利用微服务网关做登录校验
不过,这里存在几个问题:
- 1网关路由是配置的,请求转发是Gateway内部代码,我们如何在转发之前做登录校验?
- 2网关校验JWT之后,如何将用户信息传递给微服务?
- 3微服务之间也会相互调用,这种调用不经过网关,又该如何传递用户信息?
最终请求转发是有一个名为NettyRoutingFilter的过滤器来执行的,而且这个过滤器是整个过滤器链中顺序最靠后的一个。如果我们能够定义一个过滤器,在其中实现登录校验逻辑,并且将过滤器执行顺序定义到NettyRoutingFilter之前,这就符合我们的需求了(在转发之前做登录校验)
那么,该如何实现一个网关过滤器呢?
网关过滤器链中的过滤器有两种:
- GatewayFilter:路由过滤器,作用范围比较灵活,可以是任意指定的路由Route.
- GlobalFilter:全局过滤器,作用范围是所有路由,不可配置。
spring cloud gateway GatewayFilter
自定义GlobalFilter来完成登录校验
网关转微服务获取用户信息
现在,网关已经可以完成登录校验并获取登录用户身份信息。但是当网关将请求转发到微服务时,微服务又该如何获取用户身份呢?
由于网关发送请求到微服务依然采用的是Http请求,因此我们可以将用户信息以请求头的方式传递到下游微服务。然后微服务可以从请求头中获取登录用户信息。考虑到微服务内部可能很多地方都需要用到登录用户信息,因此我们可以利用SpringMVC的拦截器来实现登录用户信息获取,并存入ThreadLocal,方便后续使用。
因此,接下来我们要做的事情有:
- 改造网关过滤器,在获取用户信息后保存到请求头,转发到下游微服务
- 编写微服务拦截器,拦截请求获取用户信息,保存到ThreadLocal后放行
由于每个微服务都有获取登录用户的需求,因此拦截器我们直接写在hm-common中,并写好自动装配。这样微服务只需要引入hm-common就可以直接具备拦截器功能,无需重复编写
要点:
- 自定义拦截器 implements HandlerInterceptor
- 编写SpringMVC的配置类,配置登录拦截器 implements WebMvcConfigurer
- SpringMVC的配置类与其它微服务的扫描包不一致,无法被扫描。基于SpringBoot的自动装配原理,我们要将其添加到resources目录下的META-INF/spring.factories文件中
openFeign传递微服务之间的用户信息
前端发起的请求都会经过网关再到微服务,由于我们之前编写的过滤器和拦截器功能,微服务可以轻松获取登录用户信息。
但有些业务是比较复杂的,请求到达微服务后还需要调用其它多个微服务。
下单的过程中,需要调用商品服务扣减库存,调用购物车服务清理用户购物车。而清理购物车时必须知道当前登录的用户身份。但是,订单服务调用购物车时并没有传递用户信息,购物车服务无法知道当前用户是谁!
由于微服务获取用户信息是通过拦截器在请求头中读取,因此要想实现微服务之间的用户信息传递,就必须在微服务发起调用时把用户信息存入请求头。
微服务之间调用是基于OpenFeign来实现的,并不是我们自己发送的请求。我们如何才能让每一个由OpenFeign发起的请求自动携带登录用户信息呢?
这里要借助Feign中提供的一个拦截器接口:
feign.RequestInterceptor
我们只需要实现这个接口,然后实现apply方法,利用RequestTemplate类来添加请求头,将用户信息保存到请求头中。这样以来,每次OpenFeign发起请求的时候都会调用该方法,传递用户信息。