本文在的Spring Boot + Spring Security權限控制 基礎上搭建退出登陸html
Spring Security默認的退出登陸URL爲/logout,退出登陸後,Spring Security會作以下處理:git
1.使當前的Sesion失效;github
2.清除與當前用戶關聯的RememberMe記錄;spring
3.清空當前的SecurityContext;json
4.重定向到登陸頁。springboot
- 自定義退出: 在Spring Security配置中添加自定義退出的url,推出成功後跳轉到 /signout/success(切記須要將其加入到無需認證的列表中)
@Component @EnableGlobalMethodSecurity(prePostEnabled = true) // 開啓權限註解 public class MySecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private MyAuthenticationFailureHandler authenticationFailureHandler; @Autowired private MyAuthenticationSuccessHandler authenticationSuccessHandler; @Autowired private ValidateCodeFilter validateCodeFilter; @Autowired private UserDetailService userDetailService; @Autowired private DataSource dataSource; @Autowired private MyAuthenticationAccessDeniedHandler myAuthenticationAccessDeniedHandler; public PersistentTokenRepository persistentTokenRepository() { JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl(); jdbcTokenRepository.setDataSource(dataSource); jdbcTokenRepository.setCreateTableOnStartup(false); return jdbcTokenRepository; } @Bean public BCryptPasswordEncoder bCryptPasswordEncoder(){ return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加驗證碼校驗過濾器 .exceptionHandling() .accessDeniedHandler(myAuthenticationAccessDeniedHandler) .and() .formLogin() // 表單登陸 // http.httpBasic() // HTTP Basic .loginPage("/authentication/require") // 登陸跳轉 URL .loginProcessingUrl("/login") // 處理表單登陸 URL .failureHandler(authenticationFailureHandler) // 處理登陸失敗 .successHandler(authenticationSuccessHandler) .and() .rememberMe() // 啓用rememberMe .tokenRepository(persistentTokenRepository()) // 配置 token 持久化倉庫 .tokenValiditySeconds(3600) // remember 過時時間,單爲秒 .userDetailsService(userDetailService) // 處理自動登陸邏輯 .and() .authorizeRequests() // 受權配置 .antMatchers("/authentication/require", "/login.html", "/code/image", "/signout/success").permitAll() // 無需認證的請求路徑 .anyRequest() // 全部請求 .authenticated() // 都須要認證 .and() .logout() .logoutUrl("/signout") // 退出登陸的url .logoutSuccessUrl("/signout/success") // 退出登陸成功跳轉的url .deleteCookies("JSESSIONID") // 刪除名爲'JSESSIONID'的cookie .and().csrf().disable(); } }
- 修改IndexController:
@RestController public class IndexController { @GetMapping("index") public Object index(){ return SecurityContextHolder.getContext().getAuthentication(); } @GetMapping("/auth/admin") @PreAuthorize("hasAuthority('admin')") public String authenticationTest() { return "您擁有admin權限,能夠查看"; } @GetMapping("/signout/success") public String logoutSuccess() { System.out.println("退出成功,請從新登陸"); return "退出成功,請從新登陸"; } }
登錄成功:cookie
token表中:app
訪問http://localhost:6006/signout, 退出登陸:ide
token表中: ui
退出成功,請求重定向到了/signout/success
- 使用自定義退出成功處理器來處理退出成功後的邏輯:
實現退出成功處理器:
@Component public class MyLogOutSuccessHandler implements LogoutSuccessHandler { @Override public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException { httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value()); httpServletResponse.setContentType("application/json;charset=utf-8"); httpServletResponse.getWriter().write("退出成功,請從新登陸"); } }
修改Security配置類,添加退出成功處理器:
@Component @EnableGlobalMethodSecurity(prePostEnabled = true) // 開啓權限註解 public class MySecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private MyAuthenticationFailureHandler authenticationFailureHandler; @Autowired private MyAuthenticationSuccessHandler authenticationSuccessHandler; @Autowired private ValidateCodeFilter validateCodeFilter; @Autowired private UserDetailService userDetailService; @Autowired private DataSource dataSource; @Autowired private MyAuthenticationAccessDeniedHandler myAuthenticationAccessDeniedHandler; @Autowired private MyLogOutSuccessHandler myLogOutSuccessHandler; public PersistentTokenRepository persistentTokenRepository() { JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl(); jdbcTokenRepository.setDataSource(dataSource); jdbcTokenRepository.setCreateTableOnStartup(false); return jdbcTokenRepository; } @Bean public BCryptPasswordEncoder bCryptPasswordEncoder(){ return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加驗證碼校驗過濾器 .exceptionHandling() .accessDeniedHandler(myAuthenticationAccessDeniedHandler) .and() .formLogin() // 表單登陸 // http.httpBasic() // HTTP Basic .loginPage("/authentication/require") // 登陸跳轉 URL .loginProcessingUrl("/login") // 處理表單登陸 URL .failureHandler(authenticationFailureHandler) // 處理登陸失敗 .successHandler(authenticationSuccessHandler) .and() .rememberMe() // 啓用rememberMe .tokenRepository(persistentTokenRepository()) // 配置 token 持久化倉庫 .tokenValiditySeconds(3600) // remember 過時時間,單爲秒 .userDetailsService(userDetailService) // 處理自動登陸邏輯 .and() .authorizeRequests() // 受權配置 .antMatchers("/authentication/require", "/login.html", "/code/image", "/signout/success").permitAll() // 無需認證的請求路徑 .anyRequest() // 全部請求 .authenticated() // 都須要認證 .and() .logout() .logoutUrl("/signout") // 退出登陸的url // .logoutSuccessUrl("/signout/success") .logoutSuccessHandler(myLogOutSuccessHandler) // 配置退出成功處理騎 .deleteCookies("JSESSIONID") // 刪除名爲'JSESSIONID'的cookie .and().csrf().disable(); } }
訪問http://localhost:6006/signout, 退出成功後:
本文代碼運行正常
本文源代碼:https://github.com/ttdys/springboot/tree/master/springboot_security/06_logout