Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring mvc Spring安全性无效会话重定向_Spring Mvc_Spring Security_Spring Boot_Expired Sessions - Fatal编程技术网

Spring mvc Spring安全性无效会话重定向

Spring mvc Spring安全性无效会话重定向,spring-mvc,spring-security,spring-boot,expired-sessions,Spring Mvc,Spring Security,Spring Boot,Expired Sessions,我在SpringBoot1.2.3Web应用程序中使用SpringSecurity4.0.1(也使用SpringSession1.0.1,但这与本例无关) 我有一个私人区域和一个所有访问区域(“/about”、“/”、“/contact”……超过20页),每个用户都可以访问。(就像一家网上商店) 无论何时登录的用户会话过期,Spring都会检测到无效会话并将用户重定向到'.invalidSessionUrl(“/session/error/invalid”) 然而,我只想被重定向,如果目标链接在

我在SpringBoot1.2.3Web应用程序中使用SpringSecurity4.0.1(也使用SpringSession1.0.1,但这与本例无关)

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

无论何时登录的用户会话过期,Spring都会检测到无效会话并将用户重定向到'.invalidSessionUrl(“/session/error/invalid”)

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

我怎样才能避免呢

谢谢

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

我怎样才能做到这一点


非常感谢。

您可以提供一个自定义会话身份验证策略来完成此操作。例如:

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);
    }
}
使用静态方法很重要,因为这是一个需要在早期初始化的BeanPostProcessor


PS,我会考虑将你的配置格式化为

@ RobWinch——这看起来是一个非常常见的用例,你提出的解决方案似乎不适用于我运行的测试和评论。我相信有人提出了类似的问题,但似乎从未得到解决。我的想法是拥有多个http设置(使用xml配置)


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

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

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()
,在我的例子中,它只有一条路径,因此非常简单。

看,这里没有按预期工作。这似乎不起作用。据我所知,如果他的所有访问区域都是一个许可证,那么用户将被关联到一个匿名AuthenticationToken,在SessionManagementFilter中,访问sessionAuthenticationStrategy.onAuthentication调用的唯一方法是如果以下检查为真(authentication!=null&!trustResolver.isAnonymous(authentication))。如果用户是匿名的,它将失败并直接转到可能调用invalidSessionStrategy.onInvalidSessionDetected的代码块,该代码块将执行重定向。当前的想法是添加自定义的InvalidSession策略
<http pattern="/aboutUs**" security="none" />
<http pattern="/contact**" security="none" />
etc
http
    .expiredSessionStrategy(e -> {
        handleExpiredInvalidSessions(e.getRequest(), e.getResponse());
    })
    .sessionRegistry(sessionRegistry())
    .and()
    .invalidSessionStrategy((request, response) -> {
        handleExpiredInvalidSessions(request, response);
    })
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);
    }
}