spring boot(2.3.10)安全框架记住我会导致非安全页面出错

cu6pst1q  于 2021-09-29  发布在  Java
关注(0)|答案(1)|浏览(217)

我正在使用持久的记忆我功能。它大部分时间都在工作,但偶尔也会引发cookietheftexception。甚至对于匿名页面(用户不必登录)。为了解决这个问题。。。我创建了@exceptionhandler方法,如下所示,将用户重定向到同一页面并删除会话。但是getrequesturl()给出了/error url,而不是来自浏览器的url。我想我错过了一个获取原始url的方法,或者可能有其他更好的方法来处理它。

@ControllerAdvice
public class CookieTheftExceptionHandler implements ErrorViewResolver {

@Override
    @ExceptionHandler(RememberMeAuthenticationException.class)
    public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
        log.warn("RememberMe authentication occurred for url={}, redirecting the user to login page, error: {}", request.getRequestURL());
        String redirectURL = request.getRequestURL();
        redirectURL = redirectURL == null ? Attributes.LOGIN_URL : redirectURL;
        if (redirectURL.contains("/error"))
            redirectURL = Attributes.LOGIN_URL;
        clearSession(request);
        log.info("Redirecting the user to URL: {}", redirectURL);
        return new ModelAndView(Views.REDIRECT + redirectURL);

    }

private void clearSession(HttpServletRequest request) {
        try {
            HttpSession session = request.getSession(false);
            if (session != null) {
                session.invalidate();
            }
            SecurityContext context = SecurityContextHolder.getContext();
            context.setAuthentication(null);
            SecurityContextHolder.clearContext();
        } catch (Exception ex) {
            log.warn("Not able to clear user's session", ex);
        }

    }

}

知道为什么request.getrequesturl()将结果调用到/error输出中吗。如果这不是正确的方法,如何处理好它。我想要的是,当用户在非安全页面上时,如果“记住我”中存在问题……只需清除该用户并将其视为匿名用户即可。

uqzxnwby

uqzxnwby1#

我找到了一个解决方案,但不确定这是否是解决这个问题的“正确方法”。把它放在这里,以防有人发现它有用。
背景:spring security使用PersistentTokenBasedMemberMeservices类来处理基于持久令牌的验证。我创建了自己的自定义TokenBasedMemberMeservices类,将PersistentTokenBasedMemberMeservices中的所有代码复制到该类中。除了类名之外,代码完全相同。在ProcessAutologyCookie(..)方法中,我修改了抛出cookietheftexception的代码。相反,我抛出了rememberAuthenticationException。这解决了我的问题,不需要编写exceptionhandler。代码如下:

My SecurityConfig class:
    ..
    ..
    .and()
                .csrf().disable()
                .exceptionHandling().accessDeniedPage("/user/403/")
            .and()
                .rememberMe()
                .rememberMeParameter("remember-me")
                .rememberMeServices(tokenBasedRememberMeServices);
tokenBasedRememberMeServices is autowired to this class.

TokenBasedMemberMeservices(仅更改代码):

@Service("tokenBasedRememberMeServices")
    public class TokenBasedRememberMeServices extends AbstractRememberMeServices {

    @Autowired(required = true)
        public TokenBasedRememberMeServices(@Value("${app.security.remember-me.key}") String key,
                @Qualifier("userInfoService") UserDetailsService userDetailsService,
                @Qualifier("rememberMePersistentTokenRepository") PersistentTokenRepository tokenRepository) {
            super(key, userDetailsService);
            random = new SecureRandom();
            this.tokenRepository = tokenRepository;
        }
    protected UserDetails processAutoLoginCookie(String[] cookieTokens, HttpServletRequest request, HttpServletResponse response) {
    ...
    ..
    // We have a match for this user/series combination
            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());
                String errorMessage = messages.getMessage("PersistentTokenBasedRememberMeServices.cookieStolen",
                        "Invalid remember-me token (Series/token) mismatch. Implies previous cookie theft attack.");
                log.warn("request token doesn't match with the one stored in database, {}", errorMessage);
                throw new RememberMeAuthenticationException(errorMessage);
            }
    ....
    ....
    }

相关问题