V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Asuka0947
V2EX  ›  Java

请教一个 Java 问题

  •  
  •   Asuka0947 · 2023-09-01 18:07:40 +08:00 · 1387 次点击
    这是一个创建于 450 天前的主题,其中的信息可能已经有所发展或是发生改变。

    目前改造一个老项目,用的 eureka+fegin 这一套 A:网页消费端 B:负责登录 C:具体业务

    A 在调用 B 完成登录后,把登录信息存储到 session 中,项目业务所有登录信息都从 session 中获取

    HttpSession session = httpServletRequest.getSession(); session.setAttribute("admin", admin);

    现在由于业务需求,需要增加 token 支持第三方登录,我就在拦截器里面做了些修改

            
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
            String token = httpServletRequest.getHeader("token");
            Admin admin = getAdmin(token)
            // 假设已经获取到了用户
             HttpSession session = httpServletRequest.getSession();
            session.setAttribute("admin", admin);
    		return true ;
        }
           
    

    在登录完成后把登陆信息写到 session 中 用 postman 测试接口发现了一个问题,第一次由 A 调 C 时,在 C 业务中无法获取到 session 中的 admin 信息,null 异常,拦截器日志校验显示通过了,但是第二次调用又可以获取到 session 中的 admin 信息了。两次请求都可以在请求头了找到 token ,但是只有第一次无法获取到用户信息。 加了断点发现,第一次调用,request 并没有把 session 存放到 cookie 中放到请求头里转给 C 业务,第二次调用是有的,我看了下项目里的 fegin 转发请求头配置也是同样的,第一次请求在请求头里是找不到 cookie 的

    @Configuration
    public class FeignRequestInterceptor implements RequestInterceptor {
        @Override
        public void apply(RequestTemplate requestTemplate) {
            //通过 RequestContextHolder 获取本地请求
            RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
            if (requestAttributes == null) {
                System.out.println("requestAttributes is null");
                return;
            }
            //获取本地线程绑定的请求对象
            HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
            //给请求模板附加本地线程头部信息,主要是 cookie 信息
            Enumeration<String> headerNames = request.getHeaderNames();
            while (headerNames.hasMoreElements()) {
                String name = headerNames.nextElement();
                Enumeration<String> values = request.getHeaders(name);
                while (values.hasMoreElements()) {
                    String value = values.nextElement();
                    requestTemplate.header(name, value);
                }
            }
        }
    }
    

    想询问下问题到底出在哪里了?

    3 条回复    2023-09-02 11:59:48 +08:00
    mmdsun
        1
    mmdsun  
       2023-09-01 20:27:45 +08:00 via iPhone
    “第一次调用,request 并没有把 session 存放到 cookie 中放到请求头里转给 C 业务,第二次调用是有的。”

    这么看可能还是 RequestInterceptor 拦截器的问题,是不是多线程的环境?比如有异步注解,或者断路器? RequestInterceptor 加个打印当前线程 ID 看看,feign 客户端开启详细请求日志看看。

    看起来是通过转发 cookie 实现登录状态的吧!建议统一用 token 登录。spring session 也能配置,加个 HeaderHttpSessionIdResolver.xAuthToken ,向下游传个 ID ,就能拿到会话状态了。
    ZZ74
        2
    ZZ74  
       2023-09-01 21:24:31 +08:00
    第一次调用 Admin admin = getAdmin(token)
    返回了 null 也就是 admin 是 null

    B 服务给你 token 后没及时写入信息到缓存或者数据库中

    然而这又有什么用呢 我还是失业中... 哈哈
    uselessVisitor
        3
    uselessVisitor  
       2023-09-02 11:59:48 +08:00
    分布式 session 问题把,用 redis 存一下?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3908 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 04:16 · PVG 12:16 · LAX 20:16 · JFK 23:16
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.