我知道,有很多关于这个主题的文章,但我遇到了问题,我找不到任何解决方案。
我有一个经典的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应用程序,每次重新加载时,我都会通过调用以下控制器方法来检查用户是否已通过身份验证:
@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);
}
}
您是否知道我在配置和注销过程中遗漏了什么?
答案 0 :(得分:30)
从您的问题,我看到您正在尝试创建自己的注销,并且您还尝试使用默认的spring注销。我建议您应该选择一种方法,但不要将它们混合在一起。我可以通过两种方式向您展示从春天退出:
首先:默认的春季安全注销
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/logout.done").deleteCookies("JSESSIONID")
.invalidateHttpSession(true)
从上面的示例中,您只需要在注销用户时调用/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 security config中包含第一个方法。通过使用此方法,您可以在注销完成之前和之后添加额外的操作。但是,要使用此注销,只需调用/logout
URL并且用户将手动注销。此方法将使会话无效,清除Spring安全性上下文和cookie。
除了第二种方法,如果您使用的是RequestMethod.POST
,则需要将csrf键作为帖子包含在内。另一种方法是使用隐藏输入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键作为参数,如下所示:
<a href="${pageContext.request.contextPath}/logout?${_csrf.parameterName}=${_csrf.token}">Logout</a>
多数民众赞成,希望得到帮助。
答案 1 :(得分:1)
这会有所帮助,我认为clearAuthentication(true)就足够了:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
....
@Override
protected void configure(HttpSecurity http) throws Exception
{
http
.httpBasic()
.and()
.logout().clearAuthentication(true)
.logoutSuccessUrl("/")
.deleteCookies("JSESSIONID")
.invalidateHttpSession(true)
.and()
答案 2 :(得分:0)
只要抬起头,就有Clear Site Data HTTP标头,如下所示
Clear-Site-Data: "cache", "cookies", "storage", "executionContexts"
我还帮助将对Clear-Site-Data
标头的支持添加到Spring-Security 5.2
项目中。有关实现的更多详细信息,请参见PR。
以下是其工作方式的示例
@EnableWebSecurity
static class HttpLogoutConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.logout()
.addLogoutHandler(new HeaderWriterLogoutHandler(
new ClearSiteDataHeaderWriter(SOURCE)));
}
}
其中SOURCE是以下一项或多项的vararg
"*"
清除所有内容"cache", "cookies", "storage", "executionContexts"
中的一个或多个有关更多详细信息,请参见LogoutConfigurerClearSiteDataTests.java中的示例测试。
答案 3 :(得分:0)
我通过将以下参数添加到application.properties文件来类似地解决了我的问题
spring.cache.type=NONE
答案 4 :(得分:0)