SpringSecurity系列——自定义登录退出成功处理day5-3(源于官网5.7.2版本)

482 阅读3分钟

SpringSecurity系列——自定义登录退出成功处理day5-3(源于官网5.7.2版本)

退出登录

注入 HttpSecurity bean 时,会自动应用注销功能。 默认情况下,访问 URL /logout 将通过以下方式注销用户:

  1. 使 HTTP 会话无效
  2. 清理已配置的所有 RememberMe 身份验证
  3. 清除 SecurityContextHolder
  4. 重定向到 /login?logout

但是,与配置登录功能类似,您也有多种选项来进一步自定义您的注销要求:

public SecurityFilterChain filterChain(HttpSecurity http) {
    http
        .logout(logout -> logout
            .logoutUrl("/my/logout")
            .logoutSuccessUrl("/my/index")
            .logoutSuccessHandler(logoutSuccessHandler)
            .invalidateHttpSession(true)
            .addLogoutHandler(logoutHandler)
            .deleteCookies(cookieNamesToClear)
        )
        ...
}

在这里插入图片描述

  1. 提供注销支持。
  2. 触发注销的 URL(默认为 /logout)。 如果启用 CSRF 保护(默认),则请求也必须是 POST。 有关详细信息,请参阅 Javadoc。
  3. 注销后重定向到的 URL。 默认为 /login?logout。 有关详细信息,请参阅 Javadoc。
  4. 让我们指定一个自定义 LogoutSuccessHandler。 如果指定了此项,则忽略 logoutSuccessUrl()。 有关详细信息,请参阅 Javadoc。
  5. 指定注销时是否使 HttpSession 无效。 默认情况下是这样。 在幕后配置 SecurityContextLogoutHandler。 有关详细信息,请参阅 Javadoc。
  6. 添加一个 LogoutHandler。 SecurityContextLogoutHandler 默认添加为最后一个 LogoutHandler。
  7. 允许指定注销成功时要删除的 cookie 的名称。 这是显式添加 CookieClearingLogoutHandler 的快捷方式。

通常,为了自定义注销功能,您可以添加 LogoutHandler 和/或 LogoutSuccessHandler 实现。 对于许多常见的场景,这些处理程序在使用 fluent API 时被应用在幕后。

LogoutHandler(注销处理程序)

通常,LogoutHandler 实现表示能够参与注销处理的类。 预计将调用它们来执行必要的清理。 因此,他们不应该抛出异常。 提供了各种实现:

  1. PersistentTokenBasedRememberMeServices
  2. TokenBasedRememberMeServices
  3. CookieClearingLogoutHandler
  4. CsrfLogoutHandler
  5. SecurityContextLogoutHandler
  6. HeaderWriterLogoutHandler

有关详细信息,请参阅 Remember-Me 接口和实现。

除了直接提供 LogoutHandler 实现之外,fluent API 还提供了快捷方式,这些快捷方式在后台提供了相应的 LogoutHandler 实现。 例如,deleteCookies() 允许指定在注销成功时要删除的一个或多个 cookie 的名称。 与添加 CookieClearingLogoutHandler 相比,这是一种快捷方式。

LogoutSuccessHandler (注销成功处理程序)

LogoutSuccessHandler 在 LogoutFilter 成功注销后调用,以处理例如重定向或转发到适当的目的地。 请注意,该接口与 LogoutHandler 几乎相同,但可能会引发异常。

提供了以下实现:

  1. SimpleUrlLogoutSuccessHandler
  2. HttpStatusReturningLogoutSuccessHandler

如上所述,您不需要直接指定 SimpleUrlLogoutSuccessHandler。 相反,fluent API 通过设置 logoutSuccessUrl() 提供了一个快捷方式。 这将在幕后设置 SimpleUrlLogoutSuccessHandler。 注销后将重定向到提供的 URL。 默认为 /login?logout。

HttpStatusReturningLogoutSuccessHandler 在 REST API 类型的场景中可能很有趣。 此 LogoutSuccessHandler 允许您提供要返回的纯 HTTP 状态代码,而不是在成功注销时重定向到 URL。 如果未配置,则默认返回状态码 200。

自定义登录退出成功处理(实例)

解释

根据上方官方文档的解释我们在前后端分离的项目中,并不需要用户退出后让后端进行重定向,而是要让后端提供给前端一个json数据以确定退出成功 而且我们只要对LogoutSuccessHandler接口进行实现即可

1.在SpringSecurityConfig中进行配置

主要部分

//自定义logout处理
http.logout(
		logout ->
        logout.logoutSuccessHandler(new DefineLogoutSuccessHandler())
              .invalidateHttpSession(true)
)

完整配置

package com.example.test1.config;


import com.example.test1.filter.LoginFilter;
import com.example.test1.service.impl.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationEventPublisher;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.SpringAuthorizationEventPublisher;
import org.springframework.security.config.Customizer;

import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;

import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;

@EnableWebSecurity
@Configuration
public class SpringSecurityConfig {


    private final UserDetailsServiceImpl userDetailsService;

    @Autowired
    public SpringSecurityConfig(UserDetailsServiceImpl userDetailsService) {
        this.userDetailsService = userDetailsService;
    }


    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
        AuthenticationManager authenticationManager = configuration.getAuthenticationManager();
        System.out.println(authenticationManager);
        return configuration.getAuthenticationManager();
    }

    //身份验证事件,发布 AuthenticationEventPublisher
    @Bean
    public AuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        return new DefaultAuthenticationEventPublisher(applicationEventPublisher);
    }

    //认证事件
    @Bean
    public AuthorizationEventPublisher authorizationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        return new SpringAuthorizationEventPublisher(applicationEventPublisher);
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests(
                        auth -> auth.anyRequest().authenticated()
                )
                .formLogin(Customizer.withDefaults())

                .httpBasic(Customizer.withDefaults())
                .logout(
                        logout ->
                                //自定义logout处理
                                logout.logoutSuccessHandler(new DefineLogoutSuccessHandler())
                                        .invalidateHttpSession(true)
                        

                )
                .userDetailsService(userDetailsService);
        return http.build();
    }


}

2.编写自定义退出成功处理实现LogoutSuccessHandler接口

package com.example.test1.config;


import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;

public class DefineLogoutSuccessHandler implements LogoutSuccessHandler {


    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        System.out.println("=============logout handler==============");
        System.out.println(request.getMethod());
        System.out.println(authentication.getPrincipal());
        HashMap<String, Object> data = new HashMap<>();
        data.put("status",200);
        data.put("msg","退出登录成功");
        data.put("userData",authentication.getPrincipal());
        response.setContentType("application/json;charset=UTF-8");
        String s = new ObjectMapper().writeValueAsString(data);
        response.getWriter().println(s);
    }
}

3.测试

在这里插入图片描述 在这里插入图片描述