我在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/**");
我如何实现这一目标?
非常感谢。
答案 0 :(得分:2)
@RobWinch - 这看起来像一个非常常见的用例,你提出的解决方案似乎不适用于我运行的测试和评论。提出了类似的问题我相信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发布时,似乎仍然没有明确的方法来实现这一点。
答案 1 :(得分:0)
您可以提供自定义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
答案 2 :(得分:0)
另一个可帮助我在与您类似的情况下解决此问题的解决方法是,将过期/无效会话策略添加到您的配置中,如下所示:
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()
,在我的情况下,它只是一个路径,因此非常容易。