山有木兮丶丶 2021-10-28 13:57 采纳率: 80%
浏览 283
已结题

spring security关于CookieTheftException异常:Invalid remember-me token (Series/token) mismatch

在编写好spring security的记住我之后,前台登录产生了remember-me的cookie,然后关闭浏览器再打开请求接口,此时浏览器的remember-me就消失了,在后端debug后发现AbstractRememberMeServices类里的autoLogin方法执行了两遍,第一遍运行没问题,然后第二遍走到processAutoLoginCookie方法后发现presentedToken.equals(token.getTokenValue()的值为false,也就是从tokenRepository里取出的token与接收到的解码后的cookie不一致,然后导致抛出CookieTheftException异常,之后下面的代码就会把数据库存的token和浏览器的cookie清除掉

img

更新一波
又重新跑了遍debug,发现在processAutoLoginCookie这个方法里,验证presentedToken.equals(token.getTokenValue()为true之后,还走了这一步

tokenRepository.updateToken(newToken.getSeries(), newToken.getTokenValue(), newToken.getDate());

也就是更新了token,所以在第二次验证presentedToken.equals(token.getTokenValue()时,之前的token与更新后的token不一致导致验证失败,下面是processAutoLoginCookie方法的代码

protected UserDetails processAutoLoginCookie(String[] cookieTokens,
            HttpServletRequest request, HttpServletResponse response) {

        if (cookieTokens.length != 2) {
            throw new InvalidCookieException("Cookie token did not contain " + 2
                    + " tokens, but contained '" + Arrays.asList(cookieTokens) + "'");
        }

        final String presentedSeries = cookieTokens[0];
        final String presentedToken = cookieTokens[1];

        PersistentRememberMeToken token = tokenRepository
                .getTokenForSeries(presentedSeries);

        if (token == null) {
            // No series match, so we can't authenticate using this cookie
            throw new RememberMeAuthenticationException(
                    "No persistent token found for series id: " + presentedSeries);
        }

        // We have a match for this user/series combination
      //这里验证前端传过来的token与数据库存的是否一致,第一次验证是一致的,第二次验证因为下面有个更新token的操作导致验证失败
        if (!presentedToken.equals(token.getTokenValue())) {
            // Token doesn't match series value. Delete all logins for this user and throw
            // an exception to warn them.
            tokenRepository.removeUserTokens(token.getUsername());

            throw new CookieTheftException(
                    messages.getMessage(
                            "PersistentTokenBasedRememberMeServices.cookieStolen",
                            "Invalid remember-me token (Series/token) mismatch. Implies previous cookie theft attack."));
        }

        if (token.getDate().getTime() + getTokenValiditySeconds() * 1000L < System
                .currentTimeMillis()) {
            throw new RememberMeAuthenticationException("Remember-me login has expired");
        }

        // Token also matches, so login is valid. Update the token value, keeping the
        // *same* series number.
        if (logger.isDebugEnabled()) {
            logger.debug("Refreshing persistent login token for user '"
                    + token.getUsername() + "', series '" + token.getSeries() + "'");
        }

        PersistentRememberMeToken newToken = new PersistentRememberMeToken(
                token.getUsername(), token.getSeries(), generateTokenData(), new Date());

        try {
                //在这里token更新了
            tokenRepository.updateToken(newToken.getSeries(), newToken.getTokenValue(),
                    newToken.getDate());
            addCookie(newToken, request, response);
        }
        catch (Exception e) {
            logger.error("Failed to update token: ", e);
            throw new RememberMeAuthenticationException(
                    "Autologin failed due to data access problem");
        }

        return getUserDetailsService().loadUserByUsername(token.getUsername());
    }

瞎搞了一下,之前是先记住我登录,然后登录成功后关闭浏览器再打开浏览器直接请求接口,这时remember-me的cookie和数据库里面的token都没了,后面我的步骤跟上面一样,就是关闭浏览器再打开浏览器后,先重启了一下后端再请求接口,结果发现可以正常访问了,可真是神奇

  • 写回答

1条回答 默认 最新

  • a1767028198 2021-10-28 15:18
    关注

    PersistentTokenBasedRememberMeServices默认的tokenRepository是保存到map中,你正常登陆的时候,需要自己去写入到内存中,
    如果你自己注入的msservice,String presentedSeries = cookieTokens[0]这里没问题,基本就是tokenRepository有问题了

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 系统已结题 11月5日
  • 已采纳回答 10月28日
  • 修改了问题 10月28日
  • 修改了问题 10月28日
  • 展开全部

悬赏问题

  • ¥50 永磁型步进电机PID算法
  • ¥15 sqlite 附加(attach database)加密数据库时,返回26是什么原因呢?
  • ¥88 找成都本地经验丰富懂小程序开发的技术大咖
  • ¥15 如何处理复杂数据表格的除法运算
  • ¥15 如何用stc8h1k08的片子做485数据透传的功能?(关键词-串口)
  • ¥15 有兄弟姐妹会用word插图功能制作类似citespace的图片吗?
  • ¥200 uniapp长期运行卡死问题解决
  • ¥15 latex怎么处理论文引理引用参考文献
  • ¥15 请教:如何用postman调用本地虚拟机区块链接上的合约?
  • ¥15 为什么使用javacv转封装rtsp为rtmp时出现如下问题:[h264 @ 000000004faf7500]no frame?