处理logout方法比较简单, 只需要在<http>标签里配置<logout>标签即可:
<sec:http entry-point-ref="myAuthenticationEntryPoint">
...
<sec:logout logout-url="/logout" logout-success-url="/login"/>
...
</sec:http>
这里配置了当logout成功后跳转到login页面.
也可以指定自定义的LogoutSuccessHandler, 在logout成功后做一些其他操作, 如记录日志, 更新数据库等等.
<sec:http entry-point-ref="myAuthenticationEntryPoint">
...
<sec:logout logout-url="/logout" success-handler-ref="myLogoutHandler"/>
...
</sec:http>
<bean id="myLogoutHandler" class="com.demo.security.MyLogoutHandler"></bean>
这里注意两点:
1) <logout>标签里的logout-success-url和success-handler-ref只能指定其中一个, 不能两个都指定.
2) 自定义的LogoutHandler一定要实现LogoutSuccessHandler接口. logout成功后的具体操作写在onLogoutSuccess()方法里.
那么Spring Security是怎么处理logout操作的呢?
Spring Security把logout操作交给了LogoutFilter处理.
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
if (requiresLogout(request, response)) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (logger.isDebugEnabled()) {
logger.debug("Logging out user '" + auth + "' and transferring to logout destination");
}
// 此处的handler是一个SecurityContextLogoutHandler的实例
for (LogoutHandler handler : handlers) {
handler.logout(request, response, auth);
}
// logoutSuccessHandler就是在<logout>标签里指定的自定义handler
logoutSuccessHandler.onLogoutSuccess(request, response, auth);
return;
}
chain.doFilter(request, response);
}
可以看到LogoutFilter首先把请求交给SecurityContextLogoutHandler来处理, 而SecurityContextLogoutHandler只做了两件事, 1) 把当前session无效化, 2) 从SecurityContext里注销当前授权用户.
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
Assert.notNull(request, "HttpServletRequest required");
if (invalidateHttpSession) {
HttpSession session = request.getSession(false);
if (session != null) {
logger.debug("Invalidating session: " + session.getId());
session.invalidate();
}
}
if(clearAuthentication) {
SecurityContext context = SecurityContextHolder.getContext();
context.setAuthentication(null);
}
SecurityContextHolder.clearContext();
}
然后再交给我们自定义的logoutSuccessHandler来处理.