java - Spring Security 注销不起作用 - 不清除安全上下文并且经过身份验证的用户仍然存在

标签 java spring spring-mvc spring-security

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

我有一个经典的 Spring Security java 配置:

@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);
}
...
}

另外,我有两个 Controller 方法,通过 AJAX 从我的 Web 应用程序登录/注销。

当我想注销时,我首先调用此方法,我希望清除用户 session 并从安全上下文中清除所有内容。

@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 应用程序,每次重新加载时,我都会通过调用以下 Controller 方法检查用户是否经过身份验证:

@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注销是不行的。

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

   @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);
         }
    }

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

最佳答案

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

第一:默认spring安全注销

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

从上面的例子中,您应该只需要调用 /logout每当您想注销用户时的 URL。无需创建任何@Controller来处理该注销,而不是 Spring 将有助于注销用户。您也可以在此处添加其他要使其无效的内容。

第二:以编程方式注销

@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 并且用户将被手动注销。此方法将使 session 无效,清除 Spring 安全上下文和 cookie。

除了第二种方法,如果您使用的是RequestMethod.POST ,您需要在 POST 请求中包含 CSRF key 。另一种方法是创建一个带有隐藏输入 CSRF 键的表单。这是使用 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">Logout</a>使用它。

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

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

就这些了,希望对你有帮助。

关于java - Spring Security 注销不起作用 - 不清除安全上下文并且经过身份验证的用户仍然存在,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36557294/

相关文章:

java - 我在将文本读入数组时遇到问题,我需要在此代码中更改什么?

java - 由于 'org.hibernate.HibernateException: No Session found for current thread' 异常,需要 @Transactional 注释

java - 另一个目录问题(Java)

java - 你能在JSP(Firefox和IE)中获取Windows(AD)用户ID吗?

Spring Session table-name 属性不改变表名

java - @SpringBootTest 不使用测试属性

spring-mvc - 启动tomcat时出错

java - 无法使用 Spring Data 功能绑定(bind)数据

java - Spring MVC : Resolving the view based on User-Agent

Java 视频播放器