Spring Security 注销不起作用 - 不清除安全上下文并且经过身份验证的用户仍然存在 [英] Spring Security logout does not work - does not clear security context and authenticated user still exists

查看:36
本文介绍了Spring Security 注销不起作用 - 不清除安全上下文并且经过身份验证的用户仍然存在的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道,有很多关于这个主题的文章,但我有一个问题,我找不到任何解决方案.

I know, there are many articles about this topic, but I have a problem and I can't find any solution.

我有一个经典的 spring 安全 java 配置:

I have a classic spring security java config:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private AuctionAuthenticationProvider auctionAuthenticationProvider;

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(auctionAuthenticationProvider);
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.httpBasic();

    ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry authorizeRequest = http.authorizeRequests();

    configureAdminPanelAccess(authorizeRequest);
    configureFrontApplicationAccess(authorizeRequest);
    configureCommonAccess(authorizeRequest);

    http.csrf()
        .csrfTokenRepository(csrfTokenRepository()).and()
        .addFilterAfter(csrfHeaderFilter(), CsrfFilter.class);

    http.logout()
        .clearAuthentication(true)
        .invalidateHttpSession(true);
}
...
}

此外,我有两个控制器方法,我可以通过 AJAX 从我的 Web 应用程序登录/注销.

Also, I have two controller methods, where I login/logout from my web application by AJAX.

当我想注销时,我首先调用这个方法,我希望它清除用户会话并清除安全上下文中的所有内容.

When I would like to logout, I first call this method, which I expect to clear user sessions and clear everything from the security context.

@Override
@RequestMapping(value = "/logout", method = GET, produces = APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<Boolean> logout(final HttpServletRequest request, final HttpServletResponse response) {
    Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    if (auth != null){
        new SecurityContextLogoutHandler().logout(request, response, auth);
    }

    return new ResponseEntity<>(Boolean.TRUE, HttpStatus.OK);
}

此后,我重新加载客户端 Web 应用程序,每次重新加载时,我都会通过调用以下控制器方法来检查用户是否已通过身份验证:

After this I reload my client web application and each time, when it is reloaded, I check whether the user is authenticated by calling the following controller method:

@Override
@RequestMapping(value = "/user", method = GET, produces = APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<UserDetails> user() {
    Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    if (principal instanceof UserDetails) {
        return new ResponseEntity<>((UserDetails) principal, HttpStatus.OK);
    }

    return null;
}

在这里,我将收到最后一个经过身份验证的用户.看来之前的注销方法,Spring注销是不行的.

And here I aways receive the last authenticated user. It seems that in the previous logout method, Spring logout doesn't work.

请记住,我尝试使用以下代码注销,但没有成功:

Keep in mind that I tried to logout with the following code, without any success:

   @Override
   @RequestMapping(value = "/logout", method = GET, produces = APPLICATION_JSON_UTF8_VALUE)
    public ResponseEntity<Boolean> logout(final HttpServletRequest request) {
     try {
         request.logout();

         return new ResponseEntity<>(Boolean.TRUE, HttpStatus.OK);
     } catch (ServletException ex) {
         if (LOG.isDebugEnabled()) {
             LOG.debug("There is a problem with the logout of the user", ex);
         }
    }

你知道我在配置和注销过程中遗漏了什么吗?

Are you have any idea what I miss in my config and the logout process?

推荐答案

从您的问题来看,我看到您正在尝试创建自己的注销,并且您还尝试使用默认的 Spring 注销.我建议您应该选择一种方法,而不是将它们混合使用.有两个我建议从 Spring 注销:

From your question, I see you are trying to create your own logout and you also trying to use the default Spring logout. I advise that you should choose one method and not mix them both. There are two I recommend to logout from Spring:

第一:默认 spring 安全注销

.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/logout.done").deleteCookies("JSESSIONID")
.invalidateHttpSession(true) 

从上面的例子来看,当你想注销用户时,你应该只需要调用 /logout URL.无需创建任何 @Controller 来处理注销,Spring 将帮助用户注销.您还可以在此处添加其他您想要无效的内容.

From the example above, you should only need to call the /logout URL whenever you want to logout the user. No need to create any @Controller to handle that logout instead Spring will help to log the user out. You also can add other thing you want to invalidate here.

第二:以编程方式注销

@RequestMapping(value = {"/logout"}, method = RequestMethod.POST)
public String logoutDo(HttpServletRequest request,HttpServletResponse response){
HttpSession session= request.getSession(false);
    SecurityContextHolder.clearContext();
         session= request.getSession(false);
        if(session != null) {
            session.invalidate();
        }
        for(Cookie cookie : request.getCookies()) {
            cookie.setMaxAge(0);
        }

    return "logout";
}

如果您使用这种注销方法,则不需要在 ht eSpring 安全配置中包含第一种方法.通过使用此方法,您可以在注销之前和之后添加要执行的额外操作.顺便说一句,要使用此注销,只需调用 /logout url,用户将被手动注销.此方法将使会话无效,清除 Spring 安全上下文和 cookie.

If you are using this logout approach, you don't need to include the first method in ht eSpring security config. By using this method, you can add an extra action to perform before and after logout done. BTW, to use this logout, just call the /logout url and the user will be logged out manually. This method will invalidate the session, clear Spring security context and cookies.

另外对于第二种方法,如果您使用的是RequestMethod.POST,则需要在 POST 请求中包含 CSRF 密钥.另一种方法是创建一个带有隐藏输入 CSRF 密钥的表单.这是使用 jQuery 自动生成注销链接的一些示例:

In addition for the second method, if you are using RequestMethod.POST, you need to include the CSRF key on the POST request. The alternative way is to create a form with a hidden input CSRF key. This is some example of auto generated logout link with jQuery :

$("#Logout").click(function(){
    $form=$("<form>").attr({"action":"${pageContext.request.contextPath}"+"/logout","method":"post"})
    .append($("<input>").attr({"type":"hidden","name":"${_csrf.parameterName}","value":"${_csrf.token}"}))
    $("#Logout").append($form);
    $form.submit();
});

您只需要创建一个超链接 Logout</a> 即可使用它.

You just need to create a hyperlink <a id="Logout">Logout</a> to use it.

如果您使用 RequestMethod.GET,只需在链接中包含一个 CSRF 键作为参数,如下所示:

If you are using RequestMethod.GET,just include a CSRF key as a parameter in you link like this:

<a href="${pageContext.request.contextPath}/logout?${_csrf.parameterName}=${_csrf.token}">Logout</a>

就这些,希望能帮到你.

Thats all, hope it helps.

这篇关于Spring Security 注销不起作用 - 不清除安全上下文并且经过身份验证的用户仍然存在的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆