最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot解決跨域?qū)е聅essionId不一致的實(shí)現(xiàn)方式

 更新時(shí)間:2026年04月10日 10:08:51   作者:l去留無心  
本文描述了使用SpringBoot和谷歌kaptcha做驗(yàn)證碼登錄校驗(yàn)時(shí)遇到的跨域問題,并通過設(shè)置SameSite屬性、使用https和redis等方式解決了問題

SpringBoot解決跨域?qū)е聅essionId不一致

在用谷歌的kaptcha做驗(yàn)證碼登錄校驗(yàn),將后端發(fā)布到阿里云,前端是本地啟動(dòng),用谷歌瀏覽器(版本85)訪問驗(yàn)證碼遇到了如下問題(360瀏覽器、microsoft edge未重現(xiàn))

可以定位到是瀏覽器兼容問題

代碼是這樣的:

后端先用HttpServletRequest request的getSession().setAttribute將驗(yàn)證碼存進(jìn)session,請(qǐng)求登錄的時(shí)候再用request.getSession().getAttribute來判斷,然后發(fā)現(xiàn)請(qǐng)求驗(yàn)證碼的sessionId跟請(qǐng)求登錄的sessionId不一致,導(dǎo)致提示驗(yàn)證碼一直失效。

如下為獲取驗(yàn)證碼的接口

  @ApiOperation(value = "獲取驗(yàn)證碼", notes = "此接口用于獲取驗(yàn)證碼")
    @GetMapping("captcha.jpg")
    public void captcha(HttpServletResponse response, HttpServletRequest request) throws ServletException, IOException {
        response.setHeader("Cache-Control", "no-store, no-cache");
        response.setContentType("image/jpeg");
        // 生成文字驗(yàn)證碼
        String text = producer.createText();
        // 生成圖片驗(yàn)證碼
        BufferedImage image = producer.createImage(text);
        // 保存到驗(yàn)證碼到 session
        System.out.println("=============================");
        request.getSession().setAttribute(Constants.KAPTCHA_SESSION_KEY, text);
        System.out.println("生成文字驗(yàn)證碼:" + text);
        System.out.println("獲取驗(yàn)證碼 session:" + request.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY));
        System.out.println("獲取驗(yàn)證碼 request.getSession().getId():" + request.getSession().getId());
        System.out.println("=============================");
        ServletOutputStream out = response.getOutputStream();
        ImageIO.write(image, "jpg", out);
        IOUtils.closeQuietly(out);
    }

登錄的部分接口

@ApiOperation(value = "系統(tǒng)登錄", notes = "此接口用于系統(tǒng)登錄")
    @PostMapping(value = "/login")
    public ApiResponses login(@RequestBody LoginParam loginPARAM, HttpServletRequest request) {
        String username = loginPARAM.getUsername();
        String password = loginPARAM.getPassword();
        String captcha = loginPARAM.getCaptcha();
        System.out.println("=============================");
        System.out.println("系統(tǒng)登錄時(shí) request.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY):" + request.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY));
        System.out.println("系統(tǒng)登錄時(shí) request.getSession().getId():" + request.getSession().getId());
。
。
.
}

這種方式請(qǐng)求驗(yàn)證碼的時(shí)候會(huì)帶cookie給前端,如下所示,JSESSIONID就是后端的request.getSession().getId(),登錄的時(shí)候如果設(shè)置了跨域,前端會(huì)將JSESSIONID返回給后端,后端會(huì)進(jìn)行判斷。但是現(xiàn)在的問題就是兩次的sessionId不一致。所以還是要檢查是否設(shè)置對(duì)了跨域

檢查后端設(shè)置的跨域

這是我的跨域配置類,需要注意的是

當(dāng)allowCredentials為true時(shí)

allowedOrigins盡量不要設(shè)置為 *

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // 允許跨域訪問的路徑
        registry.addMapping("/**")
                // 允許跨域訪問的源
                .allowedOrigins("http://服務(wù)器Ip:9528","http://服務(wù)器Ip:9001")
                // 允許請(qǐng)求方法
                .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
                // 預(yù)檢間隔時(shí)間
                .maxAge(168000)
                // 允許頭部設(shè)置
                .allowedHeaders("*")
                // 是否發(fā)送cookie
                .allowCredentials(true);
    }
}

前端設(shè)置的跨域

前端設(shè)置跨域主要為:axios.defaults.withCredentials = true,然后此項(xiàng)目前端如下

const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
  withCredentials: true, // send cookies when cross-domain requests
  timeout: 5000 // request timeout
})

尋思著,這樣配置也沒問題吧。

經(jīng)過度娘的助攻,終于找出了問題的源頭

新版的chrome,加強(qiáng)了防止CSRF攻擊,需要設(shè)置Cookie的SameSite屬性

SameSite的值可以填3個(gè):Strict,Lax,None.

缺省的值為Lax,而且當(dāng)你設(shè)置其為空時(shí),在新的Chrome中還是會(huì)給予默認(rèn)值Lax.

3個(gè)模式的介紹

  • Strict:嚴(yán)格模式
  • Lax:寬松模式
  • None:可以在第三方環(huán)境中發(fā)送cookie

在這種模式下,必須同時(shí)啟用Secure才行

似乎看到了黎明的曙光,上后端代碼

@Configuration
public class SpringSessionConfig {
    // 最新的chrome,設(shè)置null會(huì)默認(rèn)成lax 但是如果設(shè)置samesite為NONE,又需要設(shè)置secure。https支持secure,http不行
    @Bean
    public CookieSerializer httpSessionIdResolver() {
        DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
        cookieSerializer.setUseHttpOnlyCookie(false);
        cookieSerializer.setSameSite("None");
        cookieSerializer.setCookiePath("/");
        cookieSerializer.setUseSecureCookie(true);
        return cookieSerializer;
    }
}

然后將后端繼續(xù)發(fā)布到阿里云,然而的然而 還是翻車了。。。

再次尋求百度,然后發(fā)現(xiàn)要滿足https +SameSite("None") +SecureCookie(true)

三者條件才能在高版本的谷歌瀏覽器訪問

但是阿里云是http,那怎么辦呢

還有一種解決方法

棄用通過session校驗(yàn),可以引入redis來做判斷

上代碼:

@Autowired
private RedisTemplate redisTemplate;
 @ApiOperation(value = "獲取驗(yàn)證碼", notes = "此接口用于獲取驗(yàn)證碼")
    @GetMapping("captcha.jpg")
    public void captcha(HttpServletResponse response, HttpServletRequest request) throws ServletException, IOException {
        response.setHeader("Cache-Control", "no-store, no-cache");
        response.setContentType("image/jpeg");
        // 生成文字驗(yàn)證碼
        String text = producer.createText();
        // 生成圖片驗(yàn)證碼
        BufferedImage image = producer.createImage(text);
        // 保存到驗(yàn)證碼到 redis 設(shè)置1分鐘過期
        redisTemplate.opsForValue().set(Constants.KAPTCHA_SESSION_KEY,text,1, TimeUnit.MINUTES);
        ServletOutputStream out = response.getOutputStream();
        ImageIO.write(image, "jpg", out);
        IOUtils.closeQuietly(out);
}
 @ApiOperation(value = "系統(tǒng)登錄", notes = "此接口用于系統(tǒng)登錄")
    @PostMapping(value = "/login")
    public ApiResponses login(@RequestBody LoginParam loginPARAM, HttpServletRequest request) {
        String username = loginPARAM.getUsername();
        String password = loginPARAM.getPassword();
        String captcha = loginPARAM.getCaptcha();
        Object kaptcha = redisTemplate.opsForValue().get(Constants.KAPTCHA_SESSION_KEY);
。
。
。
}

這樣就可以解決啦

問題調(diào)整

用如上方法寫驗(yàn)證碼會(huì)有一種問題,就是當(dāng)多個(gè)用戶同時(shí)請(qǐng)求獲取驗(yàn)證碼,其中先獲取驗(yàn)證碼的人就會(huì)失效。然后做了如下改進(jìn)

我棄用了谷歌的kaptcha,重寫了驗(yàn)證碼。給redis set值的時(shí)候同時(shí)加上一個(gè)token,登錄的時(shí)候需要返回token來驗(yàn)證

續(xù)上部分代碼

  /**
     * 生成驗(yàn)證碼
     *
     * @return
     */
public CaptchaDTO getCaptcha() {
        //1.在內(nèi)存中創(chuàng)建一張圖片
        BufferedImage bi = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
        // 畫布顏色數(shù)組
        Color[] colors = new Color[]{Color.BLUE, Color.CYAN, Color.GRAY, Color.GREEN, Color.ORANGE, Color.RED, Color.BLACK};
        //2.得到圖片
        Graphics g = bi.getGraphics();
        //3.設(shè)置圖片的背影色
        setBackGround(g, WIDTH, HEIGHT);
        //4.設(shè)置圖片的邊框
        //setBorder(g,width,height);
        //5.在圖片上畫干擾線
        drawRandomLine(g, colors, WIDTH, HEIGHT);
        String random = drawRandomNum((Graphics2D) g, colors);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        try {
            ImageIO.write(bi, "jpg", outputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 對(duì)字節(jié)數(shù)組Base64編碼
        BASE64Encoder encoder = new BASE64Encoder();
        String imageCode = encoder.encode(outputStream.toByteArray()).replaceAll("\r|\n", "");
        String token = JwtTokenUtils.generateCheckCode(random);
        CaptchaDTO captchaDTO = new CaptchaDTO();
        captchaDTO.setCodeToken(token);
        captchaDTO.setImageCode(imageCode);
        // 保存到驗(yàn)證碼到 redis 設(shè)置1分鐘過期
        redisTemplate.opsForValue().set(Constants.KAPTCHA_SESSION_KEY + token, random, 1, TimeUnit.MINUTES);
        return captchaDTO;
    }
// 登錄部分代碼
    String username = loginPARAM.getUsername();
        String password = loginPARAM.getPassword();
        String imageCode = loginPARAM.getImageCode();
        String codeToken = loginPARAM.getCodeToken();
        // 校驗(yàn)驗(yàn)證碼
        String code = (String) redisTemplate.opsForValue().get(Constants.KAPTCHA_SESSION_KEY + codeToken);
        if (StringUtils.isBlank(code)) {
            ApiAssert.failure(ErrorCodeEnum.KAPTCHA_NOT_FOUND);
        }
        // 清除token,防止重用
        redisTemplate.delete(Constants.KAPTCHA_SESSION_KEY + codeToken);
        if (!imageCode.equalsIgnoreCase(code)) {
            ApiAssert.failure(ErrorCodeEnum.KAPTCHA_ERROR);
        }

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • SpringBoot中使用MyBatis-Plus詳細(xì)步驟

    SpringBoot中使用MyBatis-Plus詳細(xì)步驟

    MyBatis-Plus是MyBatis的增強(qiáng)工具,簡(jiǎn)化了MyBatis的使用,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2025-01-01
  • Java中的延遲隊(duì)列DelayQueue源碼解析

    Java中的延遲隊(duì)列DelayQueue源碼解析

    這篇文章主要介紹了Java中的延遲隊(duì)列DelayQueue源碼解析,DelayQueue是一個(gè)支持并發(fā)的無界延遲隊(duì)列,隊(duì)列中的每個(gè)元素都有個(gè)預(yù)定時(shí)間,當(dāng)線程從隊(duì)列獲取元素時(shí),只有到期元素才會(huì)出隊(duì)列,沒有到期元素則阻塞等待,需要的朋友可以參考下
    2023-12-12
  • JAVA發(fā)送HTTP請(qǐng)求的多種方式詳細(xì)總結(jié)

    JAVA發(fā)送HTTP請(qǐng)求的多種方式詳細(xì)總結(jié)

    目前做項(xiàng)目中有一個(gè)需求是這樣的,需要通過Java發(fā)送url請(qǐng)求,查看該url是否有效,這時(shí)我們可以通過獲取狀態(tài)碼來判斷,下面這篇文章主要給大家介紹了關(guān)于JAVA發(fā)送HTTP請(qǐng)求的多種方式總結(jié)的相關(guān)資料,需要的朋友可以參考下
    2023-01-01
  • 使用OkHttp3以Multipart/Form-Data方式上傳文件方式

    使用OkHttp3以Multipart/Form-Data方式上傳文件方式

    在開發(fā)過程中,使用multipart/form-data進(jìn)行圖片上傳是一個(gè)常見的需求,本文通過一個(gè)實(shí)際案例,講解了如何在項(xiàng)目中添加OkHttp3庫(kù)依賴,并使用multipart/form-data進(jìn)行圖片上傳,首先,介紹了ContentType的概念和常見類型
    2024-10-10
  • 基于Log4j2阻塞業(yè)務(wù)線程引發(fā)的思考

    基于Log4j2阻塞業(yè)務(wù)線程引發(fā)的思考

    這篇文章主要介紹了基于Log4j2阻塞業(yè)務(wù)線程引發(fā)的思考,基于很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • MyBatis控制臺(tái)顯示SQL語句的方法實(shí)現(xiàn)

    MyBatis控制臺(tái)顯示SQL語句的方法實(shí)現(xiàn)

    這篇文章主要介紹了MyBatis控制臺(tái)顯示SQL語句的方法實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • java制作仿微信錄制小視頻控件

    java制作仿微信錄制小視頻控件

    這篇文章主要介紹了java制作仿微信錄制小視頻控件的代碼,錄制小視頻非常方便,有需要的小伙伴可以參考下。
    2015-04-04
  • MyBatis入門之增刪改查+數(shù)據(jù)庫(kù)字段和實(shí)體字段不一致問題處理方法

    MyBatis入門之增刪改查+數(shù)據(jù)庫(kù)字段和實(shí)體字段不一致問題處理方法

    這篇文章主要介紹了MyBatis入門之增刪改查+數(shù)據(jù)庫(kù)字段和實(shí)體字段不一致問題處理方法,需要的朋友可以參考下
    2017-05-05
  • Maven中引入 springboot 相關(guān)依賴的方式(最新推薦)

    Maven中引入 springboot 相關(guān)依賴的方式(最新推薦)

    這篇文章主要介紹了Maven中引入 springboot 相關(guān)依賴的方式(最新推薦),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2025-04-04
  • java OpenTelemetry日志體系及缺陷解決方案

    java OpenTelemetry日志體系及缺陷解決方案

    這篇文章主要為大家介紹了java OpenTelemetry日志體系及缺陷解決方案詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01

最新評(píng)論

德保县| 仁布县| 城市| 两当县| 江川县| 铁岭县| 灯塔市| 德庆县| 合水县| 敦化市| 西乌珠穆沁旗| 安化县| 平山县| 三门峡市| 故城县| 紫阳县| 柏乡县| 眉山市| 彭泽县| 元朗区| 伊宁县| 永宁县| 雷山县| 郎溪县| 太保市| 丽江市| 芒康县| 太原市| 龙州县| 苍山县| 杭锦后旗| 乃东县| 深泽县| 长泰县| 南溪县| 乐东| 旬阳县| 乌拉特后旗| 托克逊县| 余姚市| 英山县|