Spring Security - 禁用注销重定向

28

我正在使用Spring Security和REST,将URL (/logout) 作为我的退出方法的端点。但是在调用此方法后,它会将我重定向到 (/login?logout),我知道这是Spring logOutSuccessUrl。我想取消重定向。这是我的代码:

protected void configure(HttpSecurity http) throws Exception {

    http.authorizeRequests()
         .antMatchers("/login").permitAll()
         .anyRequest().fullyAuthenticated()
         .and().requiresChannel().anyRequest().requiresSecure()
         .and().httpBasic().disable().logout()
         .disable()
       //  .logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK))
          .csrf().disable();

}
我尝试使用HttpStatusReturningLogoutSuccessHandler,但它没有起作用,即使设置logoutSuccessUrl()也没有任何变化。 你知道如何禁用这个重定向吗?

本文详细介绍如何禁用注销重定向:https://www.baeldung.com/spring-security-disable-logout-redirects - Colm Bhandal
8个回答

49

以下代码适用于我(请注意,它没有 logout().disable()

http.logout().permitAll();
http.logout().logoutSuccessHandler((new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK)));

1
尝试将Spring Security的日志级别设置为debug,这可能会给你一些提示。如果使用Spring Boot,则可以在application.properties中添加“logging.level.org.springframework.security=DEBUG”。 - Tahir Akhtar
@uncallable 你解决了吗?我也遇到了类似的问题。尝试了所有的解决方案,但都没有用。 - ddd
我正在使用 XML 配置的 spring-security 4.2.0.RELEASE,它可以正常工作。 - Younes
我们不需要显式地传递OK,因为它是默认值。 - Prashant

27

因为目前没有被接受的答案,所以我发布了我的解决方案,这对我很有效:

.logout()
.logoutUrl("/api/user/logout")
.permitAll()
.logoutSuccessHandler((httpServletRequest, httpServletResponse, authentication) -> {
    httpServletResponse.setStatus(HttpServletResponse.SC_OK);
})
.and()

在成功注销后,只需返回一个干净的HTTP_OK(200)-在这种情况下,Spring不会重定向您


1
兄弟,你让我开心了。非常感谢,这应该是被采纳的答案。 - riccardo.cardin

3

对于使用XML配置的人们,这里是与Tahir Akhtar提供的代码段相等的片段。

<http>元素内,将<logout>元素配置如下:

<logout
    logout-url          = "/some/path/for/logout"
    invalidate-session  = "true"
    delete-cookies      = "JSESSIONID"
    success-handler-ref = "httpStatusReturningLogoutSuccessHandler"
/>

同时定义httpStatusReturningLogoutSuccessHandler bean如下:

<bean
    id      = "httpStatusReturningLogoutSuccessHandler"
    class   = "org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler"
/>

2
使用此方法:
.logout().logoutSuccessUrl("enter address here where you want to go after logout")

5
OP希望取消重定向,因为/logout是从REST客户端调用的(可能是来自浏览器的AJAX请求)。 - Tahir Akhtar
1
问题是禁用重定向,而不是将其更改为不同的URL。 - Kris
这可能没有解决原帖的问题,但是它解决了我的问题。这个问题导致了循环,还有 'access="permitAll"'。谢谢! - dev4life

1
截至2022年,由于各种原因,以上答案都无法解决我的问题(使用Spring Boot 2.6.6 + Thymeleaf)。
对我有效的最简单的解决方案是实现一个带有有效CSRF令牌的POST表单。其余的登录/注销默认实现由Spring Security提供,可以立即使用。
因此,我的Web安全配置使用了Spring Boot提供的基本默认设置。
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
        .antMatchers("/resources/**").permitAll()
        .anyRequest()
        .fullyAuthenticated()
        .and().formLogin();
    }

我的模板看起来像这样(使用BS5下拉菜单):

<ul class="dropdown-menu">
    <li><a class="dropdown-item" href="#">Settings</a></li>
    <li><a class="dropdown-item" href="#">Profile</a></li>
    <li>
        <form action="/logout" method="POST">
            <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
            <button class="dropdown-item" type="submit">Sign out</button>
        </form>
    </li>
</ul>

不要牺牲安全性(除非您有充分的理由),通过禁用CSRF令牌验证http.csrf().disable()来使GET /logout无需重定向即可正常工作,因为许多粗心的文章在网上推荐此方法作为解决方案。请注意保持HTML标签不变。

1

对于logoutSuccessXXX()动作,不要忘记添加permitAll(),因为在调用logout()方法后cookie将被清除。所以我的示例解决方案是:

http
   ......
   .and()
       .logout()
           .logoutUrl("/logout")
           .logoutSuccessUrl("/logoutSuccess")
           **.permitAll()**

1
你可以尝试这个:
http.logout().logoutRequestMatcher(new AntPathRequestMatcher("/thisistomisleadlogoutfilter"));
这将把 /thisistomisleadlogoutfilter 有效地重定向到 login?logout。因此,你应该能够使用 /logout 来代替它。

0

我使用了这个:

    @ResponseStatus(HttpStatus.NO_CONTENT)
@PostMapping(value = "/oauth/revoke")
public void revokeToken(Authentication authentication) {
    ofNullable(authentication).ifPresent(auth -> {
        OAuth2AccessToken accessToken = tokenStore.getAccessToken((OAuth2Authentication) auth);

        ofNullable(accessToken).ifPresent(oAuth2AccessToken -> {
            ofNullable(oAuth2AccessToken.getRefreshToken()).ifPresent(tokenStore::removeRefreshToken);
            tokenStore.removeAccessToken(accessToken);
        });
    });
}

从这个gist中

这个方案完美地解决了问题。我推荐使用它而不是logout()重写,主要原因是它能够(嗯,它工作正常,但除此之外)保留oauth2的基本流程(/oauth/revoke),而不是使用/logout或类似的功能。

希望这有所帮助!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接