【问题标题】:Spring security invalid session redirectSpring Security 无效会话重定向
【发布时间】:2015-08-08 13:04:20
【问题描述】:

我在 spring boot 1.2.3 web 应用程序中使用 spring security 4.0.1(也使用 spring-session 1.0.1,但这与案例无关)。

我确实有一个私人区域和一个所有用户都可以访问的所有访问区域(“/about”、“/”、“/contact”……超过 20 页)。 (就像一个网上商店)

每当登录用户会话过期时,Spring 检测到无效会话并将用户重定向到 '.invalidSessionUrl("/session/error/invalid")'

但是,如果目标链接在私有区域内,我只想被重定向,而不是公共区域。

我怎样才能避免这种情况?

谢谢。

这是我的(java)配置:(更新后看到帖子)

 http
            .authorizeRequests()
            .anyRequest()
                .permitAll()
            .antMatchers("/privado/**")
                .authenticated()
            .and()
                .formLogin()
                .loginPage("/login")
                .failureUrl("/login?error")
                .defaultSuccessUrl("/")
                .successHandler(new SessionSuccessHandler())
            .and()
                .logout()
                .logoutSuccessUrl("/")
                .deleteCookies("JSESSIONID", "SESSION")
            .and()
                .sessionManagement()
                .invalidSessionUrl("/session/error/invalid")
            .sessionFixation()
            .changeSessionId()
            .maximumSessions(1)
            .expiredUrl("/session/error/expired")
            .and()
            .and()
                .csrf()
                .ignoringAntMatchers("/jolokia/**", "/v1.0/**");

我怎样才能做到这一点?

非常感谢。

【问题讨论】:

标签: spring-mvc spring-security spring-boot expired-sessions


【解决方案1】:

您可以提供自定义 SessionAuthenticationStrategy 来执行此操作。例如:

public class MatcherSessionAuthenticationStrategy implements SessionAuthenticationStrategy {

    private final SessionAuthenticationStrategy delegate;

    private final RequestMatcher matcher;

    public MatcherSessionAuthenticationStrategy(
            SessionAuthenticationStrategy delegate, RequestMatcher matcher) {
        super();
        this.delegate = delegate;
        this.matcher = matcher;
    }

    public void onAuthentication(Authentication authentication,
            HttpServletRequest request, HttpServletResponse response)
            throws SessionAuthenticationException {
        if(matcher.matches(request)) {
            delegate.onAuthentication(authentication, request, response);
        }
    }
}

然后您可以将 RequestMatcher 和 ConcurrentSessionControlAuthenticationStrategy 注入到类中。最简单的配置方法是创建一个 BeanPostProcessor:

public class ConcurrentSessionControlAuthenticationStrategyBeanPostProcessor
        implements BeanPostProcessor {

    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        if(!(bean instanceof CompositeSessionAuthenticationStrategy)) {
            return bean;
        }

        RequestMatcher matcher = antMatchers("/about", "/","/contact");
        SessionAuthenticationStrategy original = (SessionAuthenticationStrategy) bean;
        return new MatcherSessionAuthenticationStrategy(original, matcher);
    }

    /**
     * Create a {@link List} of {@link AntPathRequestMatcher} instances.
     *
     * @param httpMethod the {@link HttpMethod} to use or {@code null} for any
     * {@link HttpMethod}.
     * @param antPatterns the ant patterns to create {@link AntPathRequestMatcher}
     * from
     *
     * @return an OrRequestMatcher with a {@link List} of {@link AntPathRequestMatcher} instances
     */
    public static RequestMatcher antMatchers(
            String... antPatterns) {
        List<RequestMatcher> matchers = new ArrayList<RequestMatcher>();
        for (String pattern : antPatterns) {
            matchers.add(new AntPathRequestMatcher(pattern));
        }
        return new OrRequestMatcher(matchers);
    }
}

然后您可以将以下内容添加到您的配置中:

@Bean
public static BeanPostProcessor sessionBeanPostProcessor() {
    return new ConcurrentSessionControlAuthenticationStrategyBeanPostProcessor();
}

使用静态方法很重要,因为这是一个需要尽早初始化的 BeanPostProcessor。

PS 我会考虑将您的配置格式化为outlined in this blog

【讨论】:

  • 这似乎不起作用。据我所知,鉴于他的所有访问区域都是 permitAll 用户将关联到 AnonymousAuthenticationToken 并且在 SessionManagementFilter 中,访问 sessionAuthenticationStrategy.onAuthentication 调用的唯一方法是以下检查是否为真(身份验证!= null &&! trustResolver.isAnonymous(身份验证))。鉴于用户是匿名的,它会失败并直接转到可能会调用 invalidSessionStrategy.onInvalidSessionDetected 的代码块,该代码块将执行重定向。目前的想法是添加一个自定义的 invalidSessionStrategy
【解决方案2】:

@RobWinch - 这似乎是一个非常常见的用例,您提出的解决方案似乎不适用于我运行的测试和 cmets。我相信http://forum.spring.io/forum/spring-projects/security/94772-redirect-to-invalid-session-url-only-when-user-accesses-secured-resource 提出了类似的问题,而且似乎从未解决。我的想法是有多个http设置(使用xml配置)

<http pattern="/aboutUs**" security="none" />
<http pattern="/contact**" security="none" />
etc

当有相当多的不安全页面并且添加新的不安全页面需要更新配置时,这似乎并不理想。如果我们能为这个用例提供一个“理想”的解决方案,那就太好了。在 Spring security 4.1 版本中,似乎仍然没有明确的方法来做到这一点。

【讨论】:

    【解决方案3】:

    在与您类似的情况下帮助我处理此问题的另一种解决方法是将过期/无效会话策略添加到您的配置中,如下所示:

    http
        .expiredSessionStrategy(e -> {
            handleExpiredInvalidSessions(e.getRequest(), e.getResponse());
        })
        .sessionRegistry(sessionRegistry())
        .and()
        .invalidSessionStrategy((request, response) -> {
            handleExpiredInvalidSessions(request, response);
        })
    

    然后您将实现它以匹配公共 URI 并简单地转发请求

    private void handleExpiredInvalidSessions(HttpServletRequest request, HttpServletResponse response) {
        String requestUri = request.getRequestURI();
        if (isPublicURI(requestUri)) {
            // This will remove the invalid/expired session from the request
            // and prevent the request from failing again
            request.getSession(true).invalidate();
            RequestDispatcher dispatcher = request.getRequestDispatcher(requestUri);
            // Retry the request
            dispatcher.forward(request, response);
        } else {
            // might redirect if you wish
            response.setStatus(440);
        }
    }
    

    你仍然需要根据你想要的公共路径来实现isPublicURI(),在我的例子中它只有一个路径,所以很容易。

    【讨论】:

      猜你喜欢
      • 2013-04-27
      • 2020-08-01
      • 2020-01-23
      • 2014-06-23
      • 2012-12-26
      • 2021-08-08
      • 1970-01-01
      • 1970-01-01
      • 2012-05-18
      相关资源
      最近更新 更多