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

问题描述

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

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

我有一个经典的spring security java config:

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?

推荐答案

从你的问题,我看到你正在尝试创建自己的注销,你也尝试使用默认的春季注销。我建议你应该选择一种方法,不要混合它们。我可以通过两种方式向你展示从春季注销:

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 you should choose one method only not mixed them both.There are two way I can show you to logout from spring:

第一:默认的spring security logout

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

从上面的例子中,只要你想注销用户,你就只需要调用 / logout url。无需创建任何 @Controller 来处理该注销,而spring将有助于将用户注销。你也可以在这里添加你想让它无效的其他东西。

From 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";
}

如果您使用此注销,则无需包含第一个spring security config中的方法。通过使用此方法,您可以在注销完成之前和之后添加额外的操作。但是,要使用此注销,只需调用 / logout url,用户将手动注销这个方法会使会话无效,清除Spring安全上下文和cookie。

If you are using this logout,you doesn't need to include the first method in spring security config. By using this method,you can add extra action to do before and after logout done.Btw, to use this logout ,just call the /logout url and user will be logout manually.This method will invalidate session,clear spring security context and cookies.

除了第二种方法,如果你使用的是 RequestMethod.POST ,您需要将csrf键包含在帖子中。另一种方法是使用隐藏输入csrf键创建一个表单。这是使用jquery自动生成的注销链接的一些示例:

In addition for second method, if you are using RequestMethod.POST, you need to include the csrf key as a post. The alternative way is to create a form with 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();
});

您只需创建超链接< a id =Logout> ;退出< / a> 使用它。

You just need to create 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>

多数,希望有所帮助。

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

10-24 13:07