SpringBoot 微服务中怎么获取用户信息 token
当我们写了一个A接口,这个接口需要调用B接口,但是B接口需要包含请求头内容,比如需要用户信息、用户id等内容,由于不在同一个线程中,使用ThreadLocal
去获取数据是无法获取的,这个时候需要手动将信息放置请求头中。
前置知识
获取请求头方式
return BaseContext.getUserId();
是我随便写的不要在意!!!
第一种 ServletRequestAttributes
通过ServletRequestAttributes
获取请求。
@GetMapping("/token")
public Long getToken() {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
String token = request.getHeader("token");
return BaseContext.getUserId();
}
第二种 HttpServletRequest
@GetMapping("/token")
public Long getToken(HttpServletRequest request) {
String token = request.getHeader("token");
return BaseContext.getUserId();
}
第二种 通过注解
@GetMapping("/token")
public Long getToken(@RequestHeader("token") String token) {
return BaseContext.getUserId();
}
操作步骤
准备好两个接口还有一个OpenFeign。
OpenFeign
@FeignClient(value = "service-admin",contextId = "IndexFeignClient", path = "")
public interface IndexFeignClient {
@GetMapping("/token")
Long getToken();
}
被调用接口B
@GetMapping("/token")
public Long getToken() {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
String token = request.getHeader("token");
return BaseContext.getUserId();
}
调用接口A
@GetMapping("abc")
public String index() {
Long id = indexFeignClient.getToken();
return "欢迎访问。。。";
}
这个时候正常去调用这个接口是无法获取到token相关信息的。
可以看到是
null
,因为没有将请求头传递过来。
传递请求头
我使用的是JWT方式,这种可以存储一些信息。使用的是注解方式存入请求头。
重写以实现对Feign请求的拦截和处理,首先通过RequestContextHolder.getRequestAttributes()
方法获取ServletRequestAttributes
对象,这个对象封装了当前请求的相关信息。然后将ServletRequestAttributes
对象转换为ServletRequestAttributes
类型,并确保它不为空。
使用requestTemplate.header("token", token)
方法将获取到的token值作为请求的header添加到Feign请求模板中。这样,在发起Feign请求时,会自动将token作为请求头一并发送给目标服务。
创建UserTokenFeignInterceptor
import feign.RequestInterceptor;
import feign.RequestTemplate;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
public class UserTokenFeignInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
assert requestAttributes != null;
HttpServletRequest request = requestAttributes.getRequest();
String token = request.getHeader("token");
requestTemplate.header("token", token);
}
}
使用注解
使用@Import
将之前的UserTokenFeignInterceptor
引入。
import cn.bunny.common.utils.feign.UserTokenFeignInterceptor;
import org.springframework.context.annotation.Import;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = ElementType.TYPE)
@Import(value = UserTokenFeignInterceptor.class)
public @interface EnableUserTokenFeignInterceptor {
}
最后在接口启动类上加上这个注解,也就是在接口A的启动类上这个注解。不要加错了!!!
是接口A的启动类!!!
是接口A的启动类!!!
是接口A的启动类!!!
@EnableFeignClients(basePackages = {"cn.bunny.feign.admin"})
@SpringBootApplication
@Slf4j
@EnableUserTokenFeignInterceptor
public class ServiceWebApplication {
public static void main(String[] args) {
log.info("ServiceApplication启动...");
SpringApplication.run(ServiceWebApplication.class, args);
}
}
之后就可以看到传递成功的token