我知道,有很多关于该主题的文章,但是我有一个问题,我找不到任何解决方案。
我有一个经典的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应用程序登录/注销。
当我想注销时,我首先调用此方法,我希望该方法清除用户会话并清除安全上下文中的所有内容。
@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应用程序,并且每次重新加载客户端Web应用程序时,我都会通过调用以下控制器方法来检查用户是否已通过身份验证:
@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将有助于注销用户。您还可以在此处添加其他要失效的内容。
/logout
@Controller
第二:以编程方式注销
@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安全配置中包括第一种方法。通过使用此方法,您可以添加完成注销之前和之后的额外操作。顺便说一句,要使用此注销,只需调用/logouturl即可手动注销用户。此方法将使会话无效,清除spring安全上下文和cookie。
除第二种方法外,如果您使用RequestMethod.POST,则还需要包含csrf密钥作为帖子。另一种方法是使用隐藏的输入csrf键创建表单。这是使用jquery自动生成的注销链接的一些示例:
RequestMethod.POST
$("#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>即可使用它。
<a id="Logout">Logout</a>
如果您使用RequestMethod.GET,只需在链接中添加一个csrf键作为参数,如下所示:
RequestMethod.GET
<a href="${pageContext.request.contextPath}/logout?${_csrf.parameterName}=${_csrf.token}">Logout</a>
仅此而已,请其帮助。