Spring Security6、登錄用戶退出登錄操作


在使用過程中,如果有多個賬號,需要進行賬號切換。我們一般需要用戶先注銷當前的登錄用戶,然后在登錄另一個賬號。

這時候我們就需要使用到退出登錄的操作,在Spring Security中默認調用接口 /logout 進行登出操作,登出成功后會自動跳轉到登錄頁面。

在前后端分離的情況下,我們希望能像登錄授權那樣,登出成功后也能返回 JSON 字符串。

一、退出登錄成功處理程序

登錄失敗處理程序和登錄授權這些一樣,我們只要實現 LogoutSuccessHandler 這個接口就可以了。

import cn.hutool.core.lang.Console;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.http.ContentType;
import cn.hutool.json.JSONUtil;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 退出成功
 *
 * @author lixin
 */
@Component
public class JsonLogoutSuccessHandler implements LogoutSuccessHandler {
    @Override
    public void onLogoutSuccess(
            HttpServletRequest request, HttpServletResponse response,
            Authentication authentication
    ) throws IOException, ServletException {
        Console.log("退出成功,{}", authentication);
        Dict res = Dict.create()
                .set("code", 0)
                .set("msg", "退出成功")
                .set("data", authentication);
        ServletUtil.write(response, JSONUtil.toJsonStr(res), ContentType.JSON.toString(CharsetUtil.CHARSET_UTF_8));
    }
}

二、配置退出登錄成功處理程序

我們現在把我們寫的 退出登錄成功 處理程序配置到HttpSecurity上,這樣在 退出登錄成功 時就返回我們設置的json字符串了,完整配置看代碼。

import com.miaopasi.securitydemo.config.security.handler.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
 * Security配置類,會覆蓋yml配置文件的內容
 *
 * @author lixin
 */
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final JsonSuccessHandler successHandler;
    private final JsonFailureHandler failureHandler;
    private final JsonAccessDeniedHandler accessDeniedHandler;
    private final JsonAuthenticationEntryPoint authenticationEntryPoint;
    private final JsonLogoutSuccessHandler logoutSuccessHandler;

    @Autowired
    public SecurityConfig(JsonSuccessHandler successHandler, JsonFailureHandler failureHandler, JsonAccessDeniedHandler accessDeniedHandler, JsonAuthenticationEntryPoint authenticationEntryPoint, JsonLogoutSuccessHandler logoutSuccessHandler) {
        this.successHandler = successHandler;
        this.failureHandler = failureHandler;
        this.accessDeniedHandler = accessDeniedHandler;
        this.authenticationEntryPoint = authenticationEntryPoint;
        this.logoutSuccessHandler = logoutSuccessHandler;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/code", "/login", "/logout", "/doLogin").permitAll()
                .antMatchers("/admin/**", "/guest/**").hasRole("admin")
                .antMatchers("/guest/**").hasRole("guest")
                .anyRequest().authenticated()
                .and().formLogin()
                .usernameParameter("username")
                .passwordParameter("password")
                .loginProcessingUrl("/doLogin")
                .successHandler(successHandler)
                .failureHandler(failureHandler)
            
            	// 退出登錄,默認為/logout,這里修改接口地址為 /doLogout
                .and().logout().logoutUrl("/doLogout")
                // 設置退出登錄成功處理程序,退出成功后返回JSON字符串
                .logoutSuccessHandler(logoutSuccessHandler)
            
                .and().exceptionHandling()
                .accessDeniedHandler(accessDeniedHandler)
                .authenticationEntryPoint(authenticationEntryPoint)
                .and().cors()
                .and().csrf().disable();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .passwordEncoder(new BCryptPasswordEncoder())
                .withUser("admin")
                .password(new BCryptPasswordEncoder().encode("123456"))
                .roles("admin", "guest")
                .and()
                .withUser("user")
                .password(new BCryptPasswordEncoder().encode("000000"))
                .roles("guest");
    }
}

三、測試

我們先登錄用戶admin,然后請求接口 /admin/get ,能正常訪問。

然后我們使用get方式調用接口 /doLogout,接口返回JSON字符串:

{
  "msg": "退出成功",
  "code": 0,
  "data": {
    "authenticated": true,
    "authorities": [
      {},
      {}
    ],
    "principal": {
      "credentialsNonExpired": true,
      "authorities": [
        {},
        {}
      ],
      "enabled": true,
      "accountNonExpired": true,
      "username": "admin",
      "accountNonLocked": true
    },
    "details": {
      "remoteAddress": "127.0.0.1"
    }
  }
}

退出成功后,我們再請求接口 /admin/get ,發現返回JSON字符串:

{
  "msg": "未登錄或者登錄失效",
  "code": 1001,
  "data": "Full authentication is required to access this resource"
}

然后我們重新登錄后繼續請求接口 /admin/get ,發現正常請求到數據。

spring security系列文章請 點擊這里 查看。
這是代碼 碼雲地址
注意注意!!!項目是使用分支的方式來提交每次測試的代碼的,請根據章節來我切換分支。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM