springSecurity 退出登录

springSecurity 退出登录

​ 这个filter比较简单,它要做的事情就是拦截退出登录的请求,执行退出逻辑,执行退出完成逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
//匹配到是退出请求,默认是/logout
if (requiresLogout(request, response)) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();

if (logger.isDebugEnabled()) {
logger.debug("Logging out user '" + auth
+ "' and transferring to logout destination");
}
//执行退出逻辑
this.handler.logout(request, response, auth);
//执行退出完成成功,回掉逻辑
logoutSuccessHandler.onLogoutSuccess(request, response, auth);

return;
}

chain.doFilter(request, response);
}

修改默认退出路径

​ 下面这样配置可以修改默认退出路径,原理是创建LogoutFilter时,将里面的匹配规则改为我们设置的路径。

1
http.logout().logoutUrl("/my/logout")

​ 值得注意的是,如果开启csrf功能,则退出请求只支持post,否则可以支持四种请求方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private RequestMatcher getLogoutRequestMatcher(H http) {
if (logoutRequestMatcher != null) {
return logoutRequestMatcher;
}
if (http.getConfigurer(CsrfConfigurer.class) != null) {
this.logoutRequestMatcher = new AntPathRequestMatcher(this.logoutUrl, "POST");
}
else {
this.logoutRequestMatcher = new OrRequestMatcher(
new AntPathRequestMatcher(this.logoutUrl, "GET"),
new AntPathRequestMatcher(this.logoutUrl, "POST"),
new AntPathRequestMatcher(this.logoutUrl, "PUT"),
new AntPathRequestMatcher(this.logoutUrl, "DELETE")
);
}
return this.logoutRequestMatcher;
}

默认退出逻辑

​ 在LogoutConfigurer类里可以看到,默认会添加两个退出逻辑。

​ 首先删除session内的用户信息,再删除SecurityContextHolder保存的用户信息,这样就算退出完成了。

如果项目里用户信息是保存在数据库里的,可与添加自定义的logoutHandler

1
2
3
4
5
6
7
8
9
10
11
private LogoutFilter createLogoutFilter(H http) {
//这是是删除session,删除SecurityContextHolder
logoutHandlers.add(contextLogoutHandler);
//这个是发送事件的
logoutHandlers.add(postProcess(new LogoutSuccessEventPublishingLogoutHandler()));
LogoutHandler[] handlers = logoutHandlers.toArray(new LogoutHandler[0]);
LogoutFilter result = new LogoutFilter(getLogoutSuccessHandler(), handlers);
result.setLogoutRequestMatcher(getLogoutRequestMatcher(http));
result = postProcess(result);
return result;
}

添加自定义logoutHandler

​ 可以看到自己添加的LogoutHandler会添加到logoutHandlers这个List里。

1
2
3
4
5
6
7
8
9
10
11
http.logout().addLogoutHandler(new LogoutHandler() {
@Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
System.out.println(authentication.getPrincipal() + "退出了");
}
});

public LogoutConfigurer<H> addLogoutHandler(LogoutHandler logoutHandler) {
this.logoutHandlers.add(logoutHandler);
return this;
}

退出时自动删除Cookie

​ 下面这样配置,可以在退出时自动删除指定的Cookie

1
http.logout().deleteCookies("sessionId","usertoken");

​ 原理就是添加了CookieClearingLogoutHandler,在退出时向response添加同名cookie,将客户端的覆盖掉。

1
2
3
public LogoutConfigurer<H> deleteCookies(String... cookieNamesToClear) {
return addLogoutHandler(new CookieClearingLogoutHandler(cookieNamesToClear));
}

退出成功执行逻辑

​ 默认会重定向到/login?logout页面上,可以自定义重定向地址

1
2
//自定义退出成功Url,会重定向到此url
http.logout().logoutSuccessUrl("/my/login");

​ 重定向的原理就是用我们指定的路径创建一个SimpleUrlLogoutSuccessHandler。这个SuccessHandler调用时会做重定向操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private LogoutSuccessHandler getLogoutSuccessHandler() {
LogoutSuccessHandler handler = this.logoutSuccessHandler;
if (handler == null) {
handler = createDefaultSuccessHandler();
}
return handler;
}

private LogoutSuccessHandler createDefaultSuccessHandler() {
SimpleUrlLogoutSuccessHandler urlLogoutHandler = new SimpleUrlLogoutSuccessHandler();
urlLogoutHandler.setDefaultTargetUrl(logoutSuccessUrl);
if (defaultLogoutSuccessHandlerMappings.isEmpty()) {
return urlLogoutHandler;
}
DelegatingLogoutSuccessHandler successHandler = new DelegatingLogoutSuccessHandler(defaultLogoutSuccessHandlerMappings);
successHandler.setDefaultLogoutSuccessHandler(urlLogoutHandler);
return successHandler;
}

自定义 logoutSuccessHandler

​ 有时候退出后不想重定向,而是数据给前台(前后端分离的项目应该都是这样)。可以自定义退出成功执行逻辑,可以覆盖上面的重定向操作。

​ 下面这样就是退出成功后,输出字符串到前台。

1
2
3
4
5
6
http.logout().logoutSuccessHandler(new LogoutSuccessHandler() {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
response.getWriter().write("logou success");
}
});

多退出路径

退出后可以对页面进行重定向,也可以返回Json数据,有时候想要两者共存怎么办呢?

1
2
如访问 /api/logout,则返回json
访问 /page/logout,执行重定向到首页

也是可以做到的。

​ 首先自定义退出匹配规则,这样就能匹配多个退出路径了

1
2
3
4
5
6
//自定义退出匹配规则
http.logout().logoutRequestMatcher(new OrRequestMatcher(
new AntPathRequestMatcher("/api/logout"),
new AntPathRequestMatcher("/page/logout")
));

​ 为其中一个退出路径指定logoutSuccessHandler

1
2
3
4
5
6
7
8
//指定匹配/api/logout的退出路径,退出成功后执行逻辑
http.logout().defaultLogoutSuccessHandlerFor(new LogoutSuccessHandler() {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
response.getWriter().write("log success");
}
},new AntPathRequestMatcher("/api/logout"));

​ 剩下的那个/page/logout没有指定处理逻辑,则会走默认的重定向到logoutSuccessUrl

这样就实现了拥有两个退出方式,且返回方式不同。

所有配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

//1. 添加自定义退出路径
http.logout().logoutUrl("/my/logout");
//2. 添加自定义退出操作,如在这里修改数据库用户状态
http.logout().addLogoutHandler(new LogoutHandler() {
@Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
System.out.println(authentication.getPrincipal() + "退出了");
}
});
//3. 删除指定cookie
http.logout().deleteCookies("sessionId", "usertoken");
//4. 自定义退出成功重定向到Url
http.logout().logoutSuccessUrl("/my/login");

//5. 自定义退出成功Handler,此功能会覆盖4中的重定向操作
http.logout().logoutSuccessHandler(new LogoutSuccessHandler() {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
response.getWriter().write("logou success");
}
});

//6.自定义退出匹配规则,可以存在多个。会覆盖1中的自定义路径
http.logout().logoutRequestMatcher(new OrRequestMatcher(
new AntPathRequestMatcher("/api/logout"),
new AntPathRequestMatcher("/page/logout")
));
//7. 指定匹配/api/logout的退出路径,退出成功后执行逻辑
//满足匹配的走这里面的逻辑,不满足的走默认逻辑,默认逻辑是 4或者5
http.logout().defaultLogoutSuccessHandlerFor(new LogoutSuccessHandler() {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
response.getWriter().write("log success");
}
}, new AntPathRequestMatcher("/api/logout"));

//8.是否删除session,删除ContentSecurityHolder内的认证
http.logout().invalidateHttpSession(true);
http.logout().clearAuthentication(true);
//9.允许退出请求访问
http.logout().permitAll();

总结

SpringSecurity的退出操作很简单,也很灵活。


springSecurity 退出登录
https://www.huangchaoyu.com/218147151.html
作者
hcy
发布于
2020年7月15日
更新于
2024年8月17日
许可协议