spring security 退出
*********************
相关类及接口
LogoutFilter
public class LogoutFilter extends GenericFilterBean {
private RequestMatcher logoutRequestMatcher;
private final LogoutHandler handler;
private final LogoutSuccessHandler logoutSuccessHandler;
public LogoutFilter(LogoutSuccessHandler logoutSuccessHandler, LogoutHandler... handlers) {
this.handler = new CompositeLogoutHandler(handlers);
Assert.notNull(logoutSuccessHandler, "logoutSuccessHandler cannot be null");
this.logoutSuccessHandler = logoutSuccessHandler;
this.setFilterProcessesUrl("/logout"); //默认的处理路径为 /logout
}
public LogoutFilter(String logoutSuccessUrl, LogoutHandler... handlers) {
this.handler = new CompositeLogoutHandler(handlers);
Assert.isTrue(!StringUtils.hasLength(logoutSuccessUrl) || UrlUtils.isValidRedirectUrl(logoutSuccessUrl), () -> {
return logoutSuccessUrl + " isn't a valid redirect URL";
});
SimpleUrlLogoutSuccessHandler urlLogoutSuccessHandler = new SimpleUrlLogoutSuccessHandler();
if (StringUtils.hasText(logoutSuccessUrl)) {
urlLogoutSuccessHandler.setDefaultTargetUrl(logoutSuccessUrl);
}
this.logoutSuccessHandler = urlLogoutSuccessHandler;
this.setFilterProcessesUrl("/logout");
}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
if (this.requiresLogout(request, response)) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (this.logger.isDebugEnabled()) {
this.logger.debug("Logging out user '" + auth + "' and transferring to logout destination");
}
this.handler.logout(request, response, auth);
this.logoutSuccessHandler.onLogoutSuccess(request, response, auth);
} else {
chain.doFilter(request, response);
}
}
protected boolean requiresLogout(HttpServletRequest request, HttpServletResponse response) {
return this.logoutRequestMatcher.matches(request);
}
public void setLogoutRequestMatcher(RequestMatcher logoutRequestMatcher) {
Assert.notNull(logoutRequestMatcher, "logoutRequestMatcher cannot be null");
this.logoutRequestMatcher = logoutRequestMatcher;
}
public void setFilterProcessesUrl(String filterProcessesUrl) {
this.logoutRequestMatcher = new AntPathRequestMatcher(filterProcessesUrl);
}
}
LogoutHandler
public interface LogoutHandler {
void logout(HttpServletRequest var1, HttpServletResponse var2, Authentication var3);
}
CompositeLogoutHandler
public final class CompositeLogoutHandler implements LogoutHandler {
private final List<LogoutHandler> logoutHandlers;
public CompositeLogoutHandler(LogoutHandler... logoutHandlers) {
Assert.notEmpty(logoutHandlers, "LogoutHandlers are required");
this.logoutHandlers = Arrays.asList(logoutHandlers);
}
public CompositeLogoutHandler(List<LogoutHandler> logoutHandlers) {
Assert.notEmpty(logoutHandlers, "LogoutHandlers are required");
this.logoutHandlers = logoutHandlers;
}
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
//遍历调用 logouthandler
Iterator var4 = this.logoutHandlers.iterator();
while(var4.hasNext()) {
LogoutHandler handler = (LogoutHandler)var4.next();
handler.logout(request, response, authentication);
}
}
}
LogoutSuccessHandler
public interface LogoutSuccessHandler {
void onLogoutSuccess(HttpServletRequest var1, HttpServletResponse var2, Authentication var3) throws IOException, ServletException;
}
*********************
示例
****************
service 层
CustomUserDetailsService
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Resource
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
String username="gtlx";
String password=passwordEncoder.encode("123456");
List<GrantedAuthority> authorities=new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
return new User(username,password,authorities);
}
}
****************
config 层
WebConfig
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login/form").setViewName("login");
registry.addViewController("/logout/success").setViewName("logout");
}
}
WebSecurityConfig
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
private UserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin().loginPage("/login/form").loginProcessingUrl("/login")
.and().authorizeRequests()
.antMatchers("/hello").hasAuthority("ROLE_USER")
.antMatchers("/**").permitAll()
.and().logout().logoutUrl("/logout").invalidateHttpSession(true)
.deleteCookies("JSESSIONID").logoutSuccessUrl("/logout/success")
.and().csrf().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(initPasswordEncoder());
}
@Bean
public PasswordEncoder initPasswordEncoder(){
return new BCryptPasswordEncoder();
}
}
****************
controller 层
HelloController
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello(Principal principal){
return "hello "+principal.getName();
}
}
****************
前端页面
login.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org" xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form th:action="@{/login}" method="post" th:align="center">
用户名:<input type="text" name="username"><br>
密码 :<input type="text" name="password"><br>
<button>提交</button>
</form>
</body>
</html>
logout.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org" xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div align="center">
成功退出
</div>
</body>
</html>
*********************
使用测试
localhost:8080/hello,认证通过后
认证成功后,会在客户端添加JSESSIONID的cookie
localhost:8080/logout
退出成功后,跳转到/logout/success,同时删除cookie JSESSIONID(若不配置deleteCookies,则该cookie不删除)