过滤器丢失Cookie的解决方案

过滤器丢失Cookie的解决方案

今天碰到一个问题迟迟未能解决
本意在过滤器中拦截每一个请求,通过获取到的Cookie 信息进行强校验,但获取结果一直未空

目录


  • 首先我们要知道什么是Cookie?它是怎么产生的

首先我们要了解什么是Cookie,什么时候产生
官网是这么介绍的,一个HTTP cookie的(网络Cookie,浏览器cookie)是一小片数据的一个服务器发送到用户的网络浏览器。浏览器可以存储它并将其与下一个请求一起发送回同一服务器。通常,它用于判断两个请求是否来自同一个浏览器 - 例如,保持用户登录。它记住无状态 HTTP协议的有状态信息。

简单来说,cookie就是访问网站时生成的缓存,用于记录用户的信息,就比如你吃过的好吃的,你还想在吃。
这里不细说,详细cookie了解 可参考官网。

因为本次重点问题在于Cookie,
下列掺杂关于部分setCookie 以及获取Cookie 的代码。

代码块

当前set Cookie 的代码如下

//在当前项目中 创建Cookie 以及录入Cookie的键及value   
//当前token 为 缓存在redis 中用户数据的 key
private String setAccountVoCookie(AccountVo accountVo, HttpServletResponse response, String cookieKey) {
        if (accountVo!= null) {
            String token = UUID.randomUUID().toString().replace("-","");
            //创建一个Cookie,cookie的名字为 agency_login
            Cookie cookie = new Cookie(cookieKey, token);
            cookie.setHttpOnly(true);
            cookie.setPath("/");
            cookie.setMaxAge(-1);
            cookie.setSecure(false);
            response.addCookie(cookie);
            //将cookie 对象添加到response 对象中,这样服务器在输出response对象中的内容时
            //就会把cookie也也输出到客户端游览器中 所以在下方中我们通过request取cookie
            return token;
        }
        return "";
    }

当前getCookie 的代码如下

//通过cacheId 获取 Cookie里的值 (当前token)
//我们通过token 获取reids 中用户的 预存的信息
public static String getCacheId(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        String cacheId = null;
        logger.debug("===>cookies: {}", cookies);
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                logger.info("cookie, {}={}", cookie.getName(), cookie.getValue());
                if (StringUtils.equals("login", cookie.getName())) {
                    cacheId = cookie.getValue();
                }
            }
        }
        return cacheId;
    }

问题分析

在当前项目中,因为要校验每次请求的当前用户的角色。因此,我们需要拿到在登录时,存入response的 Cookie,
并且通过 Cookie的值 获取缓存 与 Redis 中的用户数据进行身份校验。
而当在过滤器中获取当前 request 请求的Cookie 数据时,却始终为空 , 起初认为过滤器在请求之间便已进行拦截,因此无法获取Cookie值。

这是因为 Cookies 要在请求提交过后才会生效,它无法同时读写。
因为我们 cookie 对象是存入response对象中,服务器在输出response对象中的内容时,
才会将cookie值输出到客户端游览器中,这样我们即时在request中取cookie时,cookie自然是为空。

最后找到创建Cookie 时,发现 它是在第一次登陆时便已经将cookie写入response中,而每次当前操作Request 并不属于当前一次客户端请求,因此并不是 即存即写问题。

最后在游览器控制台找到原因,当每次发出请求时
前端通过POST方式访问后端的REST接口时,发现两条请求记录,一条请求的Request MethodOptions,另一条请求的Reuest MethodPost。 

当options 进入过滤器后,因为它是伪请求,不携带任何数据,因此  在获取cookies的过程中,始终为空。

Options 分析:

简单来说, Options 预请求 就是用于检查请求请求通道是否安全
它类属与复杂请求 。
度娘一把,果然我所踩到的坑前辈们都已经踩烂了。 

W3C规范:跨域请求中,分为简单请求和复杂请求;所谓的简单请求,需要满足如下几个条件: 
- GET,HEAD,POST请求中的一种; 
- 除了浏览器在请求头上增加的信息(如Connection,User-Agent等),开发者仅可以增加Accept,Accept-Language,Content-Type等; 
- Content-Type的取值必须是以下三个:application/x-www-form-urlencoded,multipart/form-data,text/plain。

在发出复杂请求的之前,就会出现一次OPTIONS请求。 
OPTIONS请求可以被称作一次嗅探请求,通过这个方法,客户端可以在采取具体的资源请求之前,决定对资源采取何种必要措施。 

因为我们在后端接口 接受数据定义的格式都是使用application/json做数据交互的
请求内容为json的时候,是复杂请求,因此提前进行了一次OPTIONS请求。 

我们通过下方 图例做对比

1.获取Cookie 的为空 的当前请求,我们通过log 日志打印它的当前请求方法

这里写图片描述
这里写图片描述

这里可以在日志中明确看到,我们获取cookie 的值是为空

2.再比较下方成功获取cookie 数据的 请求

这里写图片描述

可以看到先后顺序,当服务器响应成功之后会正式发起一次 post / get 请求

这里写图片描述

同时  我们在 log 日志中可以也看到 , 当options 进入过滤器后,获取cookies 数据时是为空,而当 发出post 请求时候,才成功获取到 cookie 中的数据。

这里写图片描述

也就是说问题出在于,当请求进入 过滤器后被 拦截返回。
因为我们在过滤器拦截器之间,都是正常进行请求,
因此最简单的解决办法即是放行OPTIONS请求。 
通过下列方法放行 options 请求

或者在get request 的请求方法之后,进行强校验,如果为 options 直接 false 放行,我这里最后采取第一种,代码如下:
public void updateHeader (HttpServletResponse response, HttpServletRequest request) throws UnsupportedEncodingException {
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json;charset=UTF-8");
        //允许跨域
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("origin")); 
        //允许携带带Cookie
        response.setHeader("Access-Control-Allow-Credentials", "true");
        //允许使用的请求方式
        response.setHeader("Access-Control-Allow-Methods", "POST");
        //将请求中头部出现下列关键字的类型都予以支持
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
    }
问题解决,感谢大家的支持!

猜你喜欢

转载自blog.csdn.net/qq_42473410/article/details/82023463
今日推荐