微服务间用户信息共享机制

这篇具有很好参考价值的文章主要介绍了微服务间用户信息共享机制。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

文章目录前言 第一节 微服务间用户信息传递问题 第二节 解决思路 第三节 实践操作(基于Feign) 1. 调用链路说明 2. shop-common改造 3. 开启注解 4. 启动服务器测试第四节 dubbo传递用户信息1. 调用链路说明 2. shop-common 改造 3. 测试第五节 Feign和Dubbo跨服务传递用户信息 关于错误 前言 微服务间如何进行用户信息传递?只能依靠接口调用时显式通过参数传递吗?能否在传递过程中无感知呢?

本章代码已分享至Gitee: https://gitee.com/lengcz/springcloudalibaba01.git

第一节 微服务间用户信息传递问题
微服务由于跨服务了,我们如何在中间的某个服务知道当前的用户信息呢?
例如下面,用户下单的请求,用户的请求经过了 gateway>> order >> product,如果在order的时候,我们怎么样知道用户是谁?难道要请求接口传参时传递参数(用户身份信息)吗?

微服务间用户信息共享机制
第二节 解决思路
请求流程

  1. 用户通过header传递用户身份信息,请求发送到gateway
  2. gateway 将请求路由到 order
  3. order调用product



我们知道一个微服务的请求有入口,也有出口(调用)其它微服务,请求进入时,可以通过filter进行拦截,
而调用其它请求时,我们可以将用户信息传递给被调用者(微服务),我们只需要通过AOP的思想,在入口处捕获用户信息,在出口时将用户信息传递出去,这样就保证了全链路都能获取到客户端的身份信息。当我们所有的微服务都在前后插入了接收和传出的操作,那么全链路就能够获取到用户信息了。

微服务间用户信息共享机制

第三节 实践操作(基于Feign)
我们的用户信息传递是所有微服务的,因为所有微服务模块都需要进行用户信息传递,因为我们将实现定义在common模块

微服务间用户信息共享机制

order,product,user均引用common

1. 调用链路说明
Feign的远程调用是Http的方式,所以我们只需要Filter 在入口取数据,在RequestInterceptor 出口时传递数据即可。

2. shop-common改造
2.1 引入依赖

<dependency>
    <groupId>commons-lang</groupId>
    <artifactId>commons-lang</artifactId>
    <version>2.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>


2.2 定义ThreadLocal进行线程共享

package com.lcz.userinfo;
public class UserInfoContext {
    private static ThreadLocal<UserInfo> userInfo = new ThreadLocal<>();

    public static UserInfo getUser() {
        return (UserInfo) userInfo.get();
    }

    public static void setUser(UserInfo user) {
        userInfo.set(user);
    }
    
    public static void remove(){
        userInfo.remove();
    }
}


2.3 定义用户实体

package com.lcz.userinfo;
import lombok.Data;
import java.io.Serializable;

@Data
public class UserInfo implements Serializable {
    private Integer uid; //用户id
    private String username;//用户名
}


2.4 定义常量类

package com.lcz.userinfo;

public class UserInfoConstant {
    public static final String DUBBO_USER_KEY="DUBBO_USER_INFO";

    public static final String Authorization="USER_INFO";
}


2.5 编写拦截器

package com.lcz.userinfo;

import com.alibaba.fastjson.JSON;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import lombok.extern.slf4j.Slf4j;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

@Slf4j
public class TransmitUserInfoFeighClientIntercepter implements RequestInterceptor {

    public TransmitUserInfoFeighClientIntercepter() {
    }

    @Override
    public void apply(RequestTemplate requestTemplate) {
        //从应用上下文中取出user信息,放入Feign的请求头中
        UserInfo user = UserInfoContext.getUser();
        log.info("传递用户信息:"+JSON.toJSONString(user));
        if (user != null) {
            try {
                String userJson = JSON.toJSONString(user);
                requestTemplate.header(UserInfoConstant.Authorization,new String[]{URLDecoder.decode(userJson,"UTF-8")});
            } catch (UnsupportedEncodingException e) {
                log.error("用户信息设置错误",e);
            }finally {
                UserInfoContext.remove();
            }
        }
    }
}


2.6 编写过滤器

package com.lcz.userinfo;

import com.alibaba.fastjson.JSON;
import com.lcz.pojo.User;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

@Slf4j
public class TransmitUserInfoFilter implements Filter {

    public TransmitUserInfoFilter() {
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        this.initUserInfo((HttpServletRequest)request);
        chain.doFilter(request,response);
    }

    private void initUserInfo(HttpServletRequest request){
        String userJson = request.getHeader(UserInfoConstant.Authorization);
        log.info("接收用户信息:"+userJson);
        if (StringUtils.isNotBlank(userJson)) {
            try {
                userJson = URLDecoder.decode(userJson,"UTF-8");
                UserInfo userInfo = (UserInfo) JSON.parseObject(userJson,UserInfo.class);
                //将UserInfo放入上下文中
                UserInfoContext.setUser(userInfo);
            } catch (UnsupportedEncodingException e) {
                log.error("init userInfo error",e);
            }
        }
    }
}


2.7 编写注解实现类

package com.lcz.userinfo;

import org.springframework.context.annotation.Bean;
public class EnableUserInfoTransmitterAutoConfiguration {

    public EnableUserInfoTransmitterAutoConfiguration() {
    }

    @Bean
    public TransmitUserInfoFeighClientIntercepter transmitUserInfo2FeighHttpHeader(){
        return new TransmitUserInfoFeighClientIntercepter();
    }

    @Bean
    public TransmitUserInfoFilter transmitUserInfoFromHttpHeader(){
        return new TransmitUserInfoFilter();
    }
}


2.8 . 编写Enable注解,实现注解式注入

package com.lcz.userinfo;

import org.springframework.context.annotation.Import;

import java.lang.annotation.*;

@Documented
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import({EnableUserInfoTransmitterAutoConfiguration.class})
public @interface EnableUserInfoTransmitter {
}


3. 开启注解
在order,product,user模块开启用户信息传递,使用@EnableUserInfoTransmitter

微服务间用户信息共享机制

微服务间用户信息共享机制
注意: common公共模块修改了代码,注意将common模块重新maven install发布到本地仓库

4. 启动服务器测试
回到我们的流程图,下单流程有这些微服务参与了,我们启动这些服务。只要我们在product中能够获取到用户信息,就证明用户信息传递成功了。

微服务间用户信息共享机制

发起下单请求,由于我们的身份信息通过header传递,我们需要先生成一个格式正确的身份,再写入到header进行传递

    @Test
    public void testUser() throws UnsupportedEncodingException {
        UserInfo user=new UserInfo();
        user.setUid(111);
        user.setUsername("xiaowang");
        String str=  URLEncoder.encode(JSONObject.toJSONString(user),"UTF-8");
        System.out.println(str);
    }

    
生成的信息

  1. %7B%22uid%22%3A111%2C%22username%22%3A%22xiaowang%22%7D


将这个token(身份信息)放在header中发送下单请求

微服务间用户信息共享机制
我们再product微服务的日志中,可以输出用户信息,表明了用户信息从api-gateway >> order >> product 这个流程调用中,用户信息传递成功了。

微服务间用户信息共享机制


第四节 dubbo传递用户信息
在第三节,我们的改造只适合微服务之间基于feign的调用,才能传递用户信息到其它微服务。而事实上,我们现在很多微服务之间的调用是基于dubbo的,微服务之间如何通过dubbo 传递用户信息呢?
我们的解决思路依然一样的,需要微服务的前后进行插板,这样就能保证微服务通过dubbo调用时,也能实现跨服务传递用户身份了。

1. 调用链路说明
通过官方的代码架构调用链路图,我们可以知道dubbo远程调用都需要经过Filter(全类名org.apache.dubbo.rpc.Filter),因此我们只需要在消费方和生产方两边的Filter进行附带数据传输,即可实现信息的隐式传递。

微服务间用户信息共享机制
我们利用org.apache.dubbo.rpc.Filter来拦截信息,并通过其传递用户信息,而接收方可以通过org.apache.dubbo.rpc.Filter接收信息

2. shop-common 改造
基于前面的代码,我们继续改造。

2.1 引入dubbo的依赖

<!--引入dubbo-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-dubbo</artifactId>
        </dependency>



2.2 消费者传入用户信息

package com.lcz.userinfo;

import com.alibaba.dubbo.common.extension.Activate;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.rpc.*;

@Slf4j
@Activate(group = {UserInfoConstant.CONSUMER})
public class UserInfoConsumerFilter implements org.apache.dubbo.rpc.Filter {


    @Override
    public Result invoke(Invoker<?> invoker, org.apache.dubbo.rpc.Invocation invocation) throws RpcException {
//        log.info("消费方:------");
        try{
            UserInfo userInfo = UserInfoContext.getUser();
            if (null == userInfo) {
                return invoker.invoke(invocation);
            }
            invocation.getObjectAttachments().put(UserInfoConstant.DUBBO_USER_KEY, userInfo);
            return invoker.invoke(invocation);
        }finally {
            UserInfoContext.remove();
        }
    }
}


2.3 生产者接收用户信息

package com.it.userinfo;

import com.alibaba.dubbo.common.extension.Activate;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcException;

@Slf4j
@Activate(group = CommonConstants.PROVIDER)
public class UserInfoProviderFilter implements org.apache.dubbo.rpc.Filter {

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
//        log.info("生成方:------");
        Object userInfo = invocation.getObjectAttachment(UserInfoConstant.DUBBO_USER_KEY);
        if (null != userInfo) {
            UserInfoContext.setUser((UserInfo) userInfo);
        }
        return invoker.invoke(invocation);
    }
}



2.4 添加配置文件,META-INF/dubbo目录下,创建com.alibaba.dubbo.rpc.Filter文件,内容如下

微服务间用户信息共享机制

  1. userInfoConsumerFilter=com.lcz.userinfo.UserInfoConsumerFilter
  2. userInfoProviderFilter=com.lcz.userinfo.UserInfoProviderFilter


2.3. 测试

微服务间用户信息共享机制
第五节 Feign和Dubbo跨服务传递用户信息
基于我们上面的改造,各微服务不管使用Feign调用还是Dubbo调用,都可以实现用户信息的跨服务传递,解决了无法获取用户身份的问题。让跨服务之间,可以直接使用UserInfoContext.getUser(),具有单体应用的信息获取能力

UserInfo userInfo = UserInfoContext.getUser(); //获取用户信息


同时,直接传递用户身份信息,基于这个用户信息的传递思想,我们可以实现链路跟踪(Sleuth),也可以在gateway网关封装好某些内容,传递一些request信息,比如客户端IP,用户的权限。

当然了,上面的demo直接传递用户信息是不具有防伪性,我们可能使用JWT相关的技术进行鉴权等处理,在穿越网关时,将其转换为明文可操作的UserInfo,这样就保证了传递的用户信息的安全可靠性。

关于错误
如果打包common时,提示repackage failed: Unable to find main class
可以配置文章来源地址https://www.toymoban.com/news/detail-440906.html

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <mainClass>none</mainClass>     <!-- 取消查找本项目下的Main方法:为了解决Unable to find main class的问题 -->
                <classifier>execute</classifier>    <!-- 为了解决依赖模块找不到此模块中的类或属性 -->
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

到了这里,关于微服务间用户信息共享机制的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 《Git入门实践教程》前言+目录

    版本控制系统(VCS)在项目开发中异常重要,但和在校大学生的交流中知道,这个重要方向并未受到重视。具备这一技能,既是项目开发能力的体现,也可为各种面试加码。在学习体验后知道,Git多样化平台、多种操作方式、丰富的资源为业内人士提供了方便的同时,也造成

    2024年02月10日
    浏览(50)
  • FPGA学习实践之旅——前言及目录

    很早就有在博客中记录技术细节,分享一些自己体会的想法,拖着拖着也就到了现在。毕业至今已经半年有余,随着项目越来越深入,感觉可以慢慢进行总结工作了。趁着2024伊始,就先开个头吧,这篇博客暂时作为汇总篇,记录在这几个月以及之后从FPGA初学者到也算有一定

    2024年02月03日
    浏览(35)
  • Linux - 进阶 NFS 服务器 NFS文件权限与共享目录权限主次问题

            #    NFS 的权限本身没有用户密码和账户验证登录过程               ( 你可以回忆下,我们前面访问远程共享目录的时候,是没有输入账户,密码啥的,是没                 有这个步骤的)              所以客户端登录到服务器后,会把客户端的

    2024年02月04日
    浏览(37)
  • haproxy服务器对nginx服务器web服务调度负载均衡、用nfs做共享目录(脚本部署)

    目录 一、准备 二、在作为haproxy的服务器上导入以下shell执行haproxy安装 三、由于nginx服务需要用的nfs共享目录,先部署nfs 四、nginx服务器1部署 五、nginx服务器2部署同上 六、测试 一、准备 四台服务器 系统 IP 搭建服务器 centos7 192.168.1.12 haproxy centos7 192.168.1.132 nfs(rpcbind) ce

    2024年02月09日
    浏览(35)
  • Linux 系统中常见的命令,它们用于执行各种任务,包括文件和目录管理、系统信息查看、用户管理等

    以下是一些在 Linux 系统中常见的命令,它们用于执行各种任务,包括文件和目录管理、系统信息查看、用户管理等。这里列举了一些基础的命令: 文件和目录管理: ls: 列出目录内容。 ls cd: 切换当前目录。 cd /path/to/directory cp: 复制文件或目录。 cp source_file destination mv: 移动

    2024年01月19日
    浏览(36)
  • Linux服务器配置指南:网络、用户管理、共享服务及DNS配置详解

    💂 个人网站:【 海拥】【神级代码资源网站】【办公神器】 🤟 基于Web端打造的:👉轻量化工具创作平台 💅 想寻找共同学习交流的小伙伴,请点击【全栈技术交流群】 设置虚拟机的网卡为仅主机模式,并要求服务器采用双网卡, ens33 IP地址设置为192.168. 5.x/24(其中x学号),

    2024年02月05日
    浏览(40)
  • 如何保护 LDAP 目录服务中的用户安全?

    轻量级目录访问协议(LDAP)是目前主流的身份验证协议之一,由密歇根大学的 Tim Howes、Steve Kille 和 Wengyik Yeong 于1993年创建,又经过了 Internet 工程任务组(IETF)的标准化,通过网络分发目录信息,扮演了身份源(IdP)的角色。 LDAP 在现代网络中的重要性在于该协议参与共享

    2024年01月17日
    浏览(44)
  • 如何在局域网内搭建FTP服务器,实现信息共享

    如何在局域网内搭建FTP服务器,实现信息共享   首先打开 控制面板 ,点击 程序  点击程序,点击 启用或关闭windows功能 ,找到 lnternet lnformation Services 点击前面小“+”号 选中 FTP服务器 和 WEB管理工具 ,然后点击确定,提示界面出现Windows已完成请求的更改后,点击关闭 右键

    2024年02月08日
    浏览(48)
  • Eureka:服务注册-信息配置-自我保护机制

    首先在提供者服务下,添加一个依赖 在提供者yml加上 主启动类 先启动服务端, 在启动提供者 访问http://localhost:7001/           自我保护机制      有些提供者再提供的时候断掉了连接,eureka会启动自我保护机制 再提供者的pom文件加入 提供者的yml文件    这个是显示公司信

    2024年02月11日
    浏览(34)
  • 解决不允许一个用户使用一个以上用户名与一个服务器或共享资源的多重连接的问题

    用windows server 2012 r2 vl x64搭了个文件服务器,在使用时有个问题,老是用户登录有问题,提示“不允许一个用户使用一个以上用户名与一个服务器或共享资源的多重连接”。出现的原因不详,网上也没查到合理的解释。 解决方法: 1、重新启动Workstation服务 2、用命令删除当前

    2024年02月13日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包