前言
经过前面几个章节的学习,一一哥 已经带各位实现了两种方式的自动登录。咱们现在已经学会了如何自动登录,那么又该如何退出登录呢?接下来请再跟着 壹哥 把注销登录功能也实现一下吧。
一. 注销登录
1. 代码实现
我们直接在之前案例的基础上进行代码实现,这里还是在 SecurityConfig 类中配置,其实退出登录功能的实现很简单。
@EnableWebSecurity(debug = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Value("${spring.security.remember-me.key}")
private String rememberKey;
@Autowired
private DataSource dataSource;
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
tokenRepository.setDataSource(dataSource);
http.authorizeRequests()
.antMatchers("/admin/**")
.hasRole("ADMIN")
.antMatchers("/user/**")
.hasRole("USER")
.antMatchers("/app/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.permitAll()
.and()
//开启记住我功能
.rememberMe()
.userDetailsService(userDetailsService)
//1.散列加密方案
.key(rememberKey)
//2.持久化令牌方案
.tokenRepository(tokenRepository)
//7天有效期
.tokenValiditySeconds(60 * 60 * 24 * 7)
.and()
//配置退出登录功能
.logout()
//关联自己的退出登录接口
.logoutUrl("/user/logout")
//注销成功,重定向到该路径下
.logoutSuccessUrl("/login")
//与logoutSuccessUrl处理策略类似,但更灵活.
//.logoutSuccessHandler(new LogoutSuccessHandler() {
// @Override
// public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
//处理成功退出登录后的业务
// }
//})
//.addLogoutHandler(new LogoutHandler() {
// @Override
// public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
//处理退出登录业务
// }
//})
//使得session失效
.invalidateHttpSession(true)
//清除认证信息
.clearAuthentication(true)
//删除指定的cookie
.deleteCookies("cookie01","cookie02")
.and()
.csrf()
.disable();
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
复制代码
注意:当我们退出登录时,可能也需要处理实现一些业务,我们可以把退出的功能直接在 logout 接口内部实现,也可以利用 logoutSuccessHandler()方法 + addLogoutHandler()方法来实现,请参考我注释掉的代码进行实现。
2. 自定义退出登录接口
如果我们想自己编写退出登录时的业务逻辑,也可以在 UserController 中定义一个“/logout”接口,处理退出登录功能。
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("hello")
public String hello() {
return "hello, user";
}
@RequestMapping("/logout")
public void logout(HttpSession session){
session.invalidate();
System.out.println("logout执行了...");
}
}
复制代码
3. 启动项目测试
这时候我们可以直接访问"/logout"接口直接退出,会出现下图效果:
也可以通过调用我们自定义的"/user/logout"接口退出登录,执行完后,会直接重定向到我们的登录页面。
而且我们之前保存在 persistent_logins 表中的令牌信息也都被清除掉了,说明我们已经实现了退出登录功能了。
这就是注销登录功能的代码实现,是不是很简单?
二. 注销登录源码分析
掌握了注销登录的代码实现后,你可能对注销登录的底层实现很好奇,那么接下来我们就分析一下这个注销登录的底层实现原理吧。
1. 默认的 logout 接口
认证系统往往都会带有注销登录功能,所以 Spring Security 中也提供了对注销登录的支持,默认带有“/logout”接口来实现该功能。
当我们编写 SecurityConfig 类,继承 WebSecurityConfigurerAdapter 类时,这时候我们打开 WebSecurityConfigurerAdapter 类的源码,就可以在 WebSecurityConfigurerAdapter 中的 getHttp()方法中,发现默认就有对 logout()的配置实现,如下图所示。
2. logout()方法源码实现
我们点击 logout()方法,进到 logout()方法的源码中,可以看到其内部实现,关联执行一个 LogoutConfigurer 类对象。
3. LogoutConfigurer 类源码分析
我们继续进入到 LogoutConfigurer 类中,在该类中可以发现有对默认退出登录地址的属性定义。
并且在 LogoutConfigurer 类中,还通过 configure()方法添加了对 LogoutFilter 过滤器的配置。
4. LogoutFilter 过滤器
然后我们进入到 LogoutFilter 过滤器中,首先会发现在该过滤器的构造方法中传递进来了 LogoutSuccessHandler,LogoutHandler 两个重要的参数,并且添加了对“/logout”地址的配置。
因为这是一个过滤器,肯定会执行 doFilter()方法,所以我们看一下 doFilter()方法。我们会发现在 LogoutFilter 过滤器的 doFilter()方法中,可以看到在这里关联执行了我们自己配置的 LogoutHandler 和 LogoutSuccessHandler 这两个接口,分别处理退出登录和退出登录成功后的业务。
以上就是 Spring Security 中关于退出登录功能的底层实现,大家可以按照我的思路,研究一下底层实现。
至此,壹哥 就结合着源码和底层原理,给大家讲解了如何实现退出登录了。你掌握的怎么样呢?请在评论区给 一一哥 留言,说说你的感受吧!
评论