欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringCloud解決feign調(diào)用token丟失問題解決辦法

 更新時(shí)間:2024年05月18日 10:01:53   作者:一顆蘋果  
在feign調(diào)用中可能會(huì)遇到如下問題:同步調(diào)用中,token丟失,這種可以通過創(chuàng)建一個(gè)攔截器,將token做透傳來解決,異步調(diào)用中,token丟失,這種就無法直接透傳了,因?yàn)樽泳€程并沒有token,這種需要先將token從父線程傳遞到子線程,再進(jìn)行透傳

背景討論

feign請(qǐng)求

在微服務(wù)環(huán)境中,完成一個(gè)http請(qǐng)求,經(jīng)常需要調(diào)用其他好幾個(gè)服務(wù)才可以完成其功能,這種情況非常普遍,無法避免。那么就需要服務(wù)之間的通過feignClient發(fā)起請(qǐng)求,獲取需要的 資源。

認(rèn)證和鑒權(quán)

一般而言,微服務(wù)項(xiàng)目部署環(huán)境中,各個(gè)微服務(wù)都是運(yùn)行在內(nèi)網(wǎng)環(huán)境,網(wǎng)關(guān)服務(wù)負(fù)責(zé)請(qǐng)求的路由,對(duì)外通過nginx暴露給請(qǐng)求者。

這種情況下,似乎網(wǎng)關(guān)這里做一個(gè)認(rèn)證,就可以確保請(qǐng)求者是合法的,至于微服務(wù)調(diào)用微服務(wù),反正都是自己人,而且是內(nèi)網(wǎng),無所謂是否驗(yàn)證身份了。

我有一個(gè)朋友,他們公司的項(xiàng)目確實(shí)就是這樣做的,正經(jīng)的商業(yè)項(xiàng)目。

講道理,只要框架提供了這樣的功能,那么就有存在的意義,但是,如果涉及權(quán)限的校驗(yàn),微服務(wù)之間的feign調(diào)用就需要知道身份了,即需要做鑒權(quán)

token

無論是JWT、還是OAUTH2、還是shiro,大家比較公認(rèn)的認(rèn)證、鑒權(quán)方案,就是在請(qǐng)求頭中放一堆東西,然后服務(wù)提供者通過解析這些東西完成認(rèn)證和鑒權(quán),這些東西俗稱token。

在feign調(diào)用中需要解決的就是token傳遞的問題,只有請(qǐng)求發(fā)起者將正確的token傳遞給服務(wù)提供者,服務(wù)提供者才能完成認(rèn)證&鑒權(quán),進(jìn)而返回需要的資源。

問題描述

在feign調(diào)用中可能會(huì)遇到如下問題:

  • 同步調(diào)用中,token丟失,這種可以通過創(chuàng)建一個(gè)攔截器,將token做透傳來解決
  • 異步調(diào)用中,token丟失,這種就無法直接透傳了,因?yàn)樽泳€程并沒有token,這種需要先將token從父線程傳遞到子線程,再進(jìn)行透傳

解決方案

token透傳

編寫一個(gè)攔截器,在feign請(qǐng)求前,將http請(qǐng)求攜帶的token傳遞給restTemplate。

具體實(shí)現(xiàn)方式為:

  • 創(chuàng)建一個(gè)Component實(shí)現(xiàn)com.nghsmart.ar.context.RequestAttributeContext中的RequestInterceptor接口

  • 重寫apply方法

  • 通過RequestContextHolder對(duì)象獲取到RequestAttributes

  • 通過RequestAttributes對(duì)象獲取到HttpServletRequest

  • 通過HttpServletRequest對(duì)象獲取到請(qǐng)求頭

  • 在請(qǐng)求頭中把token拿出來

  • 將token塞進(jìn)restTemplate創(chuàng)建的http請(qǐng)求頭中

示例代碼:

BizFeignRequestInterceptor

import com.nghsmart.ar.context.RequestAttributeContext;
import com.nghsmart.common.core.utils.ServletUtils;
import com.nghsmart.common.core.utils.StringUtils;
import com.nghsmart.common.core.utils.ip.IpUtils;
import com.nghsmart.common.security.constant.FeignRequestHeader;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.AbstractRequestAttributes;
import org.springframework.web.context.request.FacesRequestAttributes;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
@Slf4j
@Order(1)
@Component
public class BizFeignRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
        if (null! = attributes) {
            ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) attributes;
            String token = servletRequestAttributes.getRequest().getHeader("token");
            requestTemplate.header("token",token);
        }
    }
}

token異步線程傳遞

上述添加BizFeignRequestInterceptor只能解決同步調(diào)用環(huán)境下的token傳遞問題,當(dāng)是異步線程環(huán)境下就GG了。

通過在主線程中主動(dòng)將RequestAttribute傳遞到子線程中可以解決一部分異步線程中token傳遞的問題,示例代碼如下:

RequestContextHolder.setRequestAttributes(RequestContextHolder.getRequestAttributes(), true);

但是這種方式有弊端,當(dāng)主線程先于子線程結(jié)束的時(shí)候,子線程將獲取不到RequestAttribute,原因是Tomcat會(huì)在http請(qǐng)求結(jié)束的時(shí)候清空數(shù)據(jù)。

我們可以創(chuàng)建一個(gè)InheritableThreadLocal用來保存RequestAttribute,這樣就可以完美解決問題了。

實(shí)現(xiàn)思路為:

  • 創(chuàng)建一個(gè) RequestAttributeContext,其中維護(hù)一個(gè)InheritableThreadLocal對(duì)象,用來存RequestAttributes

  • 創(chuàng)建一個(gè)RequestAttributeInterceptor,實(shí)現(xiàn)HandlerInterceptor, WebMvcConfigurer接口,用來在請(qǐng)求開始前把 RequestAttributes 存放到 RequestAttributeContext 中

  • 修改 BizFeignRequestInterceptor ,當(dāng)無法獲取到 RequestAttributes  的時(shí)候,就從 RequestAttributeContext 中獲取

  • 透傳邏輯不變

相關(guān)示例代碼如下:

RequestAttributeContext

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestAttributes;
@Slf4j
public class RequestAttributeContext {
    private static final ThreadLocal<RequestAttributes> context = new InheritableThreadLocal<>();
    public static void setAttribute(RequestAttributes attributes) {
        if (null == attributes) {
            log.debug("RequestAttributes is null");
        }
        context.set(attributes);
    }
    public static RequestAttributes getAttribute() {
        return context.get();
    }
    public static void removeAttribute() {
        context.remove();
    }
}

RequestAttributeInterceptor

import com.alibaba.fastjson.JSON;
import com.nghsmart.ar.context.RequestAttributeContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Slf4j
@Configuration
public class RequestAttributeInterceptor implements HandlerInterceptor, WebMvcConfigurer {
    /**
     * 重寫 WebMvcConfigurer 的 addInterceptors,將 RequestAttributeInterceptor 添加到攔截器列表
     *
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(this).addPathPatterns("/**").excludePathPatterns("/swagger-resources/**", "/v2/api-docs/**");
    }
    /**
     * 重寫 HandlerInterceptor 的 preHandle,在請(qǐng)求開始處理前,將 RequestAttribute 存入 RequestAttributeContext
     *
     * @param request  current HTTP request
     * @param response current HTTP response
     * @param handler  chosen handler to execute, for type and/or instance evaluation
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        RequestAttributeContext.setAttribute(requestAttributes);
        return true;
    }
}

BizFeignRequestInterceptor

import com.nghsmart.ar.context.RequestAttributeContext;
import com.nghsmart.common.core.utils.ServletUtils;
import com.nghsmart.common.core.utils.StringUtils;
import com.nghsmart.common.core.utils.ip.IpUtils;
import com.nghsmart.common.security.constant.FeignRequestHeader;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.AbstractRequestAttributes;
import org.springframework.web.context.request.FacesRequestAttributes;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
@Slf4j
@Order(1)
@Component
public class BizFeignRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
        if (null! = attributes) {
            ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) attributes;
            String token = servletRequestAttributes.getRequest().getHeader("token");
            requestTemplate.header("token",token);
        }else {
            RequestAttributes requestAttributes = RequestAttributeContext.getAttribute();
            if (null != requestAttributes) {
                RequestContextHolder.setRequestAttributes(requestAttributes);
            } else {
                log.debug("requestAttributes is null");
            }
            ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
            String token = servletRequestAttributes.getRequest().getHeader("token");
            requestTemplate.header("token",token);
        }
    }
}

到此這篇關(guān)于SpringCloud解決feign調(diào)用token丟失問題解決辦法的文章就介紹到這了,更多相關(guān)SpringCloud中feign調(diào)用token丟失內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java8 stream的分組功能實(shí)例介紹

    java8 stream的分組功能實(shí)例介紹

    這篇文章主要給大家介紹了關(guān)于java8 stream的分組功能的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用java8具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • SSM項(xiàng)目中配置LOG4J日志的方法

    SSM項(xiàng)目中配置LOG4J日志的方法

    本篇文章主要介紹了SSM項(xiàng)目中配置LOG4J日志的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-09-09
  • Java字符串中指定部分反轉(zhuǎn)的三種方式

    Java字符串中指定部分反轉(zhuǎn)的三種方式

    一些面試官可能在面試Java基礎(chǔ)的時(shí)候,讓你說一下字符串反轉(zhuǎn),會(huì)手撕代碼,所以下面這篇文章主要給大家介紹了關(guān)于Java字符串中指定部分反轉(zhuǎn)的三種方式,需要的朋友可以參考下
    2022-01-01
  • Scheduler定時(shí)任務(wù)調(diào)度詳解

    Scheduler定時(shí)任務(wù)調(diào)度詳解

    文章介紹了SysJobServiceImpl類中定時(shí)任務(wù)調(diào)度的相關(guān)方法,包括清除、檢查存在性、創(chuàng)建、暫停、恢復(fù)、刪除任務(wù),以及觸發(fā)任務(wù),并提到了JobKey、CronUtils、ScheduleUtils、SpringUtils等工具類的使用,適用于Spring管理環(huán)境
    2025-01-01
  • java利用phantomjs進(jìn)行截圖實(shí)例教程

    java利用phantomjs進(jìn)行截圖實(shí)例教程

    PlantomJs是一個(gè)基于javascript的webkit內(nèi)核無頭瀏覽器 也就是沒有顯示界面的瀏覽器,你可以在基于 webkit 瀏覽器做的事情,它都能做到。下面這篇文章主要給大家介紹了關(guān)于java利用phantomjs進(jìn)行截圖的相關(guān)資料,需要的朋友可以參考下
    2018-10-10
  • 探究MyBatis插件原理以及自定義插件實(shí)現(xiàn)

    探究MyBatis插件原理以及自定義插件實(shí)現(xiàn)

    這篇文章主要介紹了探究MyBatis插件原理以及自定義插件實(shí)現(xiàn),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-07-07
  • mybatis整合springboot報(bào)BindingException:Invalid?bound?statement?(not?found)異常解決

    mybatis整合springboot報(bào)BindingException:Invalid?bound?stateme

    這篇文章主要給大家介紹了關(guān)于mybatis整合springboot報(bào)BindingException:Invalid?bound?statement?(not?found)異常的解決辦法,這個(gè)錯(cuò)誤通常是由于Mapper文件中的statement?id與Java代碼中的方法名不一致導(dǎo)致的,需要的朋友可以參考下
    2024-01-01
  • Java中LocalCache本地緩存實(shí)現(xiàn)代碼

    Java中LocalCache本地緩存實(shí)現(xiàn)代碼

    本篇文章主要介紹了Java中LocalCache本地緩存實(shí)現(xiàn)代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-05-05
  • 解讀靜態(tài)資源訪問static-locations和static-path-pattern

    解讀靜態(tài)資源訪問static-locations和static-path-pattern

    本文主要介紹了Spring Boot中靜態(tài)資源的配置和訪問方式,包括靜態(tài)資源的默認(rèn)前綴、默認(rèn)地址、目錄結(jié)構(gòu)、訪問路徑以及靜態(tài)資源處理器的工作原理,通過配置文件和實(shí)現(xiàn)`WebMvcConfigurer`接口,可以自定義靜態(tài)資源目錄和訪問前綴
    2025-01-01
  • Spring MVC如何設(shè)置請(qǐng)求頭和響應(yīng)頭的Header

    Spring MVC如何設(shè)置請(qǐng)求頭和響應(yīng)頭的Header

    這篇文章主要介紹了Spring MVC如何設(shè)置請(qǐng)求頭和響應(yīng)頭的Header問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-03-03

最新評(píng)論