SpringSecurity——前后端分離登錄認證

SpringSecurity——前后端分離登錄認證的整個過程

前端:

使用Axios向后端發送請求

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>登錄</title><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<form>用戶名:<input type="text" name="username" id="username"><br>密碼:<input type="password" name="password" id="password"><br><input type="button" value="登錄" onclick="login()">
</form>
</body>
<script>function login() {var username = document.getElementById("username").value;var password = document.getElementById("password").value;let formData = new FormData(); // 創建formData對象formData.append("username", username);formData.append("password", password);axios.post("http://localhost:8080/login", formData).then(function (response) {console.log(response);if (response.data.code === 200) {alert("登錄成功");window.location.href = "welcome.html";} else {alert("登錄失敗");}}).catch(function (error){console.log(error);});}
</script></html>

?后端:

Spring Security 配置指定該 URL 作為登錄處理入口。

    
@Configuration
@EnableMethodSecurity
// 配置spring的容器
public class SecurityConfig {@Bean// 安全過濾器鏈Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity ,CorsConfigurationSource configurationSource ) throws Exception { //httpSecurity方法參數注入Beanreturn httpSecurity// 配置自己的登錄頁面.formLogin( (formLogin) ->{formLogin.loginProcessingUrl("/login") // 登錄賬戶密碼往哪個地址提交}) .build();}
}

由于現在是前后端分離的,所以拿不到CSRF,因此我們需要先禁用CSRF:

禁用 CSRF:

在基于 Token 的認證中,由于不依賴 Session,因此通常會關閉 CSRF 保護。可以在 HttpSecurity 中調用 .csrf().disable() 來實現這一點。

    
@Configuration
@EnableMethodSecurity
// 配置spring的容器
public class SecurityConfig {@Bean// 安全過濾器鏈Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity ,CorsConfigurationSource configurationSource ) throws Exception { //httpSecurity方法參數注入Beanreturn httpSecurity// 配置自己的登錄頁面.formLogin( (formLogin) ->{formLogin.loginProcessingUrl("/login") // 登錄賬戶密碼往哪個地址提交}) .csrf((csrf)->{// 禁止csrf跨站請求,禁用之后,肯定就不安全了,有csrf網絡攻擊的風險,后續加入jwt是可以防御的csrf.disable();}).build();}
}

配置 formLogin.loginProcessingUrl("/login") 實際上告訴 Spring Security:

  • 當收到指向 /login 的 POST 請求時,Spring Security 內部的過濾器(例如 UsernamePasswordAuthenticationFilter)會攔截這個請求,并自動處理用戶的認證邏輯。
  • 你不需要在自己的 Controller 中實現這個 /login 接口,因為 Spring Security 會接管并執行用戶名、密碼的驗證,以及后續的成功或失敗處理(如果你配置了相應的 successHandlerfailureHandler)。

存在跨域問題:

協議不同會跨域 ?https://localhost:8080????http://localhost:8080

  1. 端口不同會跨域:http://localhost:10492????http://localhost:8080?
  2. 域名不同會跨域:http://bjpowernode.com???http://baidu.com?

三個里面有任何一個不同,都是跨域,跨域是瀏覽器不允許的,瀏覽器是為了安全,不允許你跨域訪問

跨域資源共享(CORS)配置

  • 允許跨域訪問:
    前后端分離架構中,前端通常與后端不在同一個域名下,因此必須在后端配置 CORS 策略。可以通過在 HttpSecurity 配置中調用 .cors() 方法通常需要自己定義一個 CorsConfigurationSource Bean。在自己定義?CorsConfigurationSource Bean當中我們需要返回CorsConfigurationSource(接口)的實現類——通常情況下是UrlBasedCorsConfigurationSource

@Configuration
@EnableMethodSecurity
// 配置spring的容器
public class SecurityConfig {/*** 配置跨域* @return*/@Beanpublic CorsConfigurationSource configurationSource() {UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();// 跨域配置CorsConfiguration corsConfiguration = new CorsConfiguration();corsConfiguration.setAllowedOrigins(Arrays.asList("*")); // 允許的請求來源corsConfiguration.setAllowedMethods(Arrays.asList("*")); // 允許的請求方法corsConfiguration.setAllowedHeaders(Arrays.asList("*"));// 允許的請求頭// 注冊配置urlBasedCorsConfigurationSource.registerCorsConfiguration("/**",corsConfiguration);return urlBasedCorsConfigurationSource;}@Bean// 安全過濾器鏈Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity ,CorsConfigurationSource configurationSource ) throws Exception { //httpSecurity方法參數注入Beanreturn httpSecurity// 配置自己的登錄頁面.formLogin( (formLogin) ->{formLogin.loginProcessingUrl("/login") // 登錄賬戶密碼往哪個地址提交}) .csrf((csrf)->{// 禁止csrf跨站請求,禁用之后,肯定就不安全了,有csrf網絡攻擊的風險,后續加入jwt是可以防御的csrf.disable();}).cors((cors)->{ // 允許前端跨域訪問cors.configurationSource( configurationSource);}).build();}
}

憑證接收和驗證:?Spring Security框架使用 UsernamePasswordAuthenticationFilter 攔截請求,獲取用戶提交的賬號和密碼。

用戶信息查詢:

UserServiceImpl重寫loadUserByUsername方法 從數據庫中加載用戶信息,返回一個包含用戶狀態和權限信息的 UserDetails(在本例中為 TUser 對象)。

重寫loadUserByUsername方法需要service接口,需要繼承springsecurity框架的UserDetailsService接口

// 我們的處理登錄的service接口,需要繼承springsecurity框架的UserDetailsService接口
public interface UserService extends UserDetailsService {
}

service實現類?

    @Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {// 通過用戶名查詢數據庫TUser user =  userMapper.selectByLoginAct(username);if (user == null){throw new UsernameNotFoundException("用戶不存在");}return user; // 實現了UserDetails接口,包含所有字段}

狀態檢查和密碼比對: 框架會檢查用戶對象的狀態(例如賬戶是否有效)以及比對密碼是否匹配。

登錄成功或失敗的處理(處理器):

根據認證結果決定登錄成功后的跳轉(默認跳轉到上一次請求的地址或項目根路徑)或失敗后的處理(重定向到 /login?error),但在前后端分離場景中,需要通過自定義 Handler 返回 JSON 格式的響應。

@Configuration
@EnableMethodSecurity
// 配置spring的容器
public class SecurityConfig {@Bean// 安全過濾器鏈Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity ,CorsConfigurationSource configurationSource ) throws Exception { //httpSecurity方法參數注入Beanreturn httpSecurity// 配置自己的登錄頁面.formLogin( (formLogin) ->{formLogin.loginProcessingUrl("/login") // 登錄賬戶密碼往哪個地址提交.successHandler(myAuthenticationSuccessHandler).failureHandler(myAuthenticationFailHandler); // 登錄失敗的回調}) .build();}
}
?MyAuthenticationSuccessHandle(登錄成功的處理器):
@Component
public class MyAuthenticationSuccessHandle implements AuthenticationSuccessHandler {@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {R result = R.builder().code(200).msg("登錄成功").info(authentication.getPrincipal()).build();response.setContentType("application/json;charset=utf-8");String json = JSONUtil.toJsonStr(result);response.getWriter().write(json);}
}
?MyAuthenticationFailHandle(登錄失敗的處理器):
@Component
public class MyAuthenticationFailHandle implements AuthenticationFailureHandler {@Overridepublic void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {R result = R.builder().code(500).msg("登錄失敗").info(exception.getMessage()).build();response.setContentType("application/json;charset=utf-8");String json = JSONUtil.toJsonStr(result);response.getWriter().write(json);}
}
退出成功的處理器
@Component
public class MyLogoutSuccessHandler implements LogoutSuccessHandler {@Overridepublic void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {R result = R.builder().code(200).msg("退出成功").info(authentication.getPrincipal()).build();response.setContentType("application/json;charset=utf-8");String json = JSONUtil.toJsonStr(result);response.getWriter().write(json);}
}

在 Spring Security 中,退出操作(logout)的設計邏輯與登錄有所不同。登錄過程涉及用戶憑證驗證、狀態檢查和密碼匹配等環節,這些都有可能失敗,所以需要提供失敗處理器(如登錄失敗處理器)。而退出操作本質上只是清理會話、清空 SecurityContext 等動作,通常不會出現“失敗”的情況。因此,框架只提供了退出成功處理器(LogoutSuccessHandler),而沒有專門的退出失敗處理器。

無狀態認證的考慮:

由于不再使用傳統 Session 記錄用戶狀態,后續訪問其他需要認證的接口時會提示未登錄,此時通常會引入 JWT 等機制來維持用戶認證狀態。

沒有session、前端cookie中也不會存儲sessionid;那么這樣的話,用戶狀態怎么保持呢?

需要使用我們下面介紹的jwt解決該問題;

不分離的:Tomcat 【thymeleaf ?<----> (controller、sucurity)】

前后端分離:Nginx 【Vue】 ?<----jwt----> ?Tomcat 【 (controller、sucurity) 】

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/72988.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/72988.shtml
英文地址,請注明出處:http://en.pswp.cn/web/72988.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

qt下載和安裝教程國內源下載地址

qt不斷在更新中&#xff0c;目前qt6日漸成熟&#xff0c;先前我們到官方下載或者國內鏡像直接可以下載到exe文件安裝&#xff0c;但是最近幾年qt官方似乎在逐漸關閉舊版本下載通道&#xff0c;列為不推薦下載。但是qt5以其廣泛使用和穩定性&#xff0c;以及積累大量代碼使得qt5…

Mysql架構理論部分

Mysql架構是什么&#xff1f;實際可以理解為執行一條sql語句所要經歷的階段有哪些&#xff01; 1.連接層 &#xff08;1&#xff09;客戶端發起連接 客戶端通過TCP/IP、Unix Socket或命名管道等方式向Mysql服務器發起鏈接請求 想要了解tcp與udp的區別&#xff0c;可以參考這…

架構師面試(十九):IM 架構

問題 IM 系統從架構模式上包括 【介紹人模式】和 【代理人模式】。介紹人模式也叫直連模式&#xff0c;消息收發不需要服務端的參與&#xff0c;即客戶端之間直連的方式&#xff1b;代理人模式也叫中轉模式&#xff0c;消息收發需要服務端進行中轉。 下面關于這兩類模式描述的…

【服務器】RAID0、RAID1、RAID5、RAID6、RAID10異同與應用

目錄 ?編輯 一、RAID概述 1.1 磁盤陣列簡介 1.2 功能 二、RAID級別 2.1 RAID 0&#xff08;不含校驗與冗余的條帶存儲&#xff09; 2.2 RAID1&#xff08;不含校驗的鏡像存儲&#xff09; 2.3 RAID 5 &#xff08;數據塊級別的分布式校驗條帶存儲&#xff09; 4、RAI…

MySQL身份驗證的auth_socket插件

在Ubuntu 20.04 LTS上&#xff0c;MySQL 8.0默認使用auth_socket插件進行身份驗證&#xff0c;可能存在意想不到的情況。 一、auth_socket插件 在使用sudo mysql或通過sudo切換用戶后執行任何MySQL命令時&#xff0c;不需要輸入密碼或錯誤密碼都可以正常登入mysql數據庫&…

小程序開發中的用戶反饋收集與分析

我們在開發小程序的過程中根據開發過程中的代碼及業務場景,以下是針對需求管理系統的用戶反饋收集與分析方案設計: 需求管理系統用戶反饋收集與分析方案 一、反饋數據模型設計 // 新增Feedback模型(app/admin/model/Feedback.php) namespace app\admin\model; use think\…

python關鍵字匯總

文章目錄 1. 變量與類型相關2. 控制流相關3. 函數與類相關4. 異常處理相關5. 模塊相關6. 其他 在 Python 3 里有 35 個關鍵字&#xff0c;它們各自具備特定的用途與意義 1. 變量與類型相關 True、False 意義&#xff1a;布爾類型的常量&#xff0c;分別代表邏輯真與邏輯假。示…

使用Python在Word中創建、讀取和刪除列表 - 詳解

目錄 工具與設置 Python在Word中創建列表 使用默認樣式創建有序&#xff08;編號&#xff09;列表 使用默認樣式創建無序&#xff08;項目符號&#xff09;列表 創建多級列表 使用自定義樣式創建列表 Python讀取Word中的列表 Python從Word中刪除列表 在Word中&#xff…

軟考-軟件設計師-計算機網絡

一、七層模型 中繼器&#xff1a;信號會隨著距離的增加而逐漸衰減&#xff0c;中繼器可以接受一端的信息再將其原封不動的發給另一端&#xff0c;起到延長傳輸距離的作用&#xff1b; 集線器&#xff1a;多端口的中繼器&#xff0c;所有端口公用一個沖突域&#xff1b; 網橋&…

關于Flask框架30道面試題及解析

文章目錄 基礎概念1. 什么是Flask?其核心特性是什么?2. Flask和Django的主要區別?3. 解釋Flask中的“路由”概念。如何定義動態路由?核心組件4. Flask的請求上下文(Request Context)和應用上下文(Application Context)有什么區別?5. 如何訪問請求參數?POST和GET方法的…

C++20 中 `constexpr` 的強大擴展:算法、工具與復數庫的變革

文章目錄 一、constexpr 在 <algorithm> 中的應用1. 編譯時排序2. 編譯時查找 二、constexpr 在 <utility> 中的應用1. 編譯時交換2. 編譯時條件交換 三、constexpr 在 <complex> 中的應用1. 編譯時復數運算 四、總結 C20 對 constexpr 的增強是其最引人注目…

【ELK】節省存儲 之 壓縮存儲方式調整

目錄 集群版本&#xff1a; 7.17.6 解釋幾個概念&#xff1a; 段&#xff08;Segment&#xff09; 合并(Merge) 索引設置&#xff1a; 壓縮方式(index.codec)&#xff1a; 測試設置前提條件 對比 在創建的時候指定壓縮類型&#xff08;index.codec&#xff09; 對比 在…

conda create之后,以前的conda env list 只能看到環境路徑 沒有環境名稱了

1.命令 conda env list 看到的顯示如下&#xff1a; 左邊這列的"base"&#xff0c;指向的路徑和其它環境變量安裝的路徑不一致。 這時需要通過"activate [anaconda的環境路徑]"和"source activate"回到anaconda&#xff1a; 2.執行切換命令 …

夸克網盤任務腳本——進階自動版

腳本是用于自動管理和更新夸克云盤(Quark Cloud Drive)上的文件和目錄的Python腳本。其主要功能包括自動下載、更新、重命名、刪除文件和文件夾,以及處理和發送通知,可以在特定的時間間隔內運行,根據配置文件進行操作。 主要功能 1. Quark 類: __init__:初始化類,設置…

AsyncHttpClient使用說明書

[[toc]] AsyncHttpClient(AHC)是一個高性能、異步的 HTTP 客戶端庫,廣泛用于 Java 和 Scala 應用中,特別適合處理高并發、非阻塞的 HTTP 請求。它基于 Netty 或 Java 原生的異步 HTTP 客戶端實現,支持 HTTP/1.1 和 HTTP/2 協議,適用于微服務、API 調用、爬蟲等場景。 1.…

Powershell、Windows Shell、CMD 的區別與聯系

Powershell、Windows Shell、CMD 的區別與聯系 一、核心概念 名稱 全稱 類型 發布時間 CMD Command Prompt 命令行解釋器&#xff08;CLI&#xff09; 1985&#xff08;DOS&#xff09; Powershell Windows PowerShell 任務自動化腳本環境 2006 Windows Shell Wi…

vulnhub-Tr0ll ssh爆破、wireshark流量分析,exp、尋找flag。思維導圖帶你清晰拿到所以flag

vulnhub-Tr0ll ssh爆破、wireshark流量分析&#xff0c;exp、尋找flag。思維導圖帶你清晰拿到所以flag 1、主機發現 arp-scan -l 2、端口掃描 nmap -sS -sV 192.168.66.185 nmap -sS -A -T4 -p- 192.168.66.185 nmap --scriptvuln 192.168.66.185經典掃描三件套&#xff0c;…

強化學習(趙世鈺版)-學習筆記(8.值函數方法)

本章是算法與方法的第四章&#xff0c;是TD算法的拓展&#xff0c;本質上是將狀態值與行為值的表征方式&#xff0c;從離散的表格形式&#xff0c;拓展到了連續的函數形式。 表格形式的優點是直觀&#xff0c;便于分析&#xff0c;缺點是數據量較大或者連續性狀態或者行為空間時…

[特殊字符] 2025藍橋杯備賽Day7——B2117 整理藥名

&#x1f50d; 2025藍橋杯備賽Day7——B2117 整理藥名 題目難度&#xff1a;?? 適合掌握字符串基礎操作 考察重點&#xff1a;大小寫轉換、字符串遍歷、邊界條件處理 B2117 整理藥名 題目描述 醫生在書寫藥品名的時候經常不注意大小寫&#xff0c;格式比較混亂。現要求你…

笛卡爾軌跡規劃之齊次變換矩陣與歐拉角、四元數的轉化

一、笛卡爾軌跡規劃需求 笛卡爾軌跡規劃本質就是我們對機械臂的末端位置和姿態進行規劃&#xff0c;其實也就是對末端坐標系的位姿進行規劃。我們清楚末端坐標系的位姿是可以用齊次變換矩陣T來表示的&#xff0c;但這樣表示的話&#xff0c;并不利于我們去做規劃&#xff0c;所…