解决 feign 远程调用 请求头丢失问题:

问题一:解决 feign 远程调用 验证失败问题:

我们在接入了SpringSecurity之后,请求的时候都会在header中带上JWT令牌,这样才能访问资源。假设这样一个情景:已经完成了认证服务的认证,前端页面的header现在是带着JWT令牌的,前端需要访问A服务,而在A服务中,需要通过Feign来远程调用B服务,A、B服务都是接入了SpringSecurity的。以下为图示:
解决 feign 远程调用 请求头丢失问题:_第1张图片

  1. 前端请求A服务的时候,header中是带了token的,因为A服务需要认证,认证通过。
  2. A服务远程调用B服务,如果不做处理的话,因为B服务也需要认证,这时A服务是无法成功调用B服务的,因为A服务的请求没带token,无法通过B服务的认证,会被SpringSecurity拦截下来,造成调用失败。

这时可以想一个办法,让token一直在header头中传递下去:

  1. 使用全局配置设置Feign客户端的认证令牌:您可以在Feign客户端的全局配置中设置认证令牌,这样每个Feign请求都会自动包含该令牌。在您的A服务中,创建一个Feign配置类,并使用RequestInterceptor来设置"Authorization"头部,将JWT令牌添加到每个Feign请求中。这样,无论A服务调用哪个远程服务,都会自动带上认证令牌。
package com.ds.user.config;

import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

@Configuration
public class FeignConfig implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {

        // 在您的代码中获取JWT令牌的逻辑
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String token = request.getHeader("token");
        // 从当前请求的上下文中获取JWT令牌
//        String token = // 获取JWT令牌的逻辑,例如从请求的Header中获取

        System.out.println("我是token  我被调用了");
        // 将JWT令牌添加到Feign请求的Header中
        if (token != null) {
            requestTemplate.header("token",token);
        }
    }
}

实现:
解决 feign 远程调用 请求头丢失问题:_第2张图片

问题二:解决多线程 feign远程调用 验证失败问题:

第一步:

我们要使用 InheritableThreadLocal 来进行存储token

在多线程环境中,ThreadLocal的值在不同线程之间是独立的,无法共享。这意味着您在一个线程中设置的token值,在另一个线程中是无法直接获取到的。

要在多线程环境中实现token的共享,您可以考虑使用InheritableThreadLocal而不是ThreadLocal来存储token值。InheritableThreadLocal允许子线程继承父线程的token值。这样,当您在父线程中设置token时,子线程就能够获取到正确的token值。

首先定义一个utils 类:

public class TokenHolder {
    private static final InheritableThreadLocal<String> tokenHolder = new InheritableThreadLocal<>();

    public static String getToken() {
        return tokenHolder.get();
    }

    public static void setToken(String token) {
        tokenHolder.set(token);
    }

    public static void clearToken() {
        tokenHolder.remove();
    }
}

第二步:

在我们使用到多线程之前就 可以把 token 存到 tokenHolder 中了。 调用其中的 setToken 方法即可

第三步:

然后,在FeignConfigapply方法中使用TokenHolder.getToken()来获取token值: (可以和上面配合使用)

public class FeignConfig implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        String token = TokenHolder.getToken();
        // ...
        // 添加其他逻辑
        // ...
    }
}

你可能感兴趣的:(java,前端,servlet,spring,boot,spring,cloud)