Spring Boot登錄認證實現學習心得:從皮膚信息系統項目中學到的經驗

前言

最近通過一個皮膚信息管理系統的項目實踐,深入學習了Spring Boot框架中登錄認證功能的實現方式。這個項目涵蓋了從后端配置到前端集成的完整流程,讓我對現代Web應用的安全機制有了更深刻的理解。本文將分享我在這個過程中的學習心得和技術要點。

一、JWT認證機制的理解與實現

1.1 為什么選擇JWT

傳統的Session認證方式在分布式系統中存在擴展性問題,而JWT(JSON Web Token)作為一種無狀態的認證機制完美解決了這個問題。在項目中,我們采用了JWT來實現用戶認證,主要優勢在于:

  • ??無狀態??:服務端不需要存儲會話信息
  • ??跨域支持??:適合前后端分離架構
  • ??自包含??:所有必要信息都包含在token中

1.2 JWT工具類實現

@Component
public class JwtUtils {private static final String SECRET = "your-secret-key";private static final long EXPIRATION = 86400000L; // 24小時public static String generateToken(UserDetails userDetails) {return Jwts.builder().setSubject(userDetails.getUsername()).setIssuedAt(new Date()).setExpiration(new Date(System.currentTimeMillis() + EXPIRATION)).signWith(SignatureAlgorithm.HS512, SECRET).compact();}public static String getUsernameFromToken(String token) {return Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token).getBody().getSubject();}public static boolean validateToken(String token, UserDetails userDetails) {final String username = getUsernameFromToken(token);return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));}private static boolean isTokenExpired(String token) {final Date expiration = getExpirationDateFromToken(token);return expiration.before(new Date());}
}

二、Spring Security整合實踐

2.1 安全配置類

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate UserDetailsService userDetailsService;@Autowiredprivate JwtAuthenticationEntryPoint unauthorizedHandler;@Beanpublic JwtAuthenticationFilter jwtAuthenticationFilter() {return new JwtAuthenticationFilter();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.cors().and().csrf().disable().exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests().antMatchers("/api/auth/**").permitAll().antMatchers("/api/test/**").permitAll().anyRequest().authenticated();http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);}
}

2.2 自定義認證過濾器

public class JwtAuthenticationFilter extends OncePerRequestFilter {@Autowiredprivate JwtUtils jwtUtils;@Autowiredprivate UserDetailsService userDetailsService;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {try {String jwt = parseJwt(request);if (jwt != null && jwtUtils.validateToken(jwt)) {String username = jwtUtils.getUsernameFromToken(jwt);UserDetails userDetails = userDetailsService.loadUserByUsername(username);UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));SecurityContextHolder.getContext().setAuthentication(authentication);}} catch (Exception e) {logger.error("Cannot set user authentication: {}", e);}filterChain.doFilter(request, response);}private String parseJwt(HttpServletRequest request) {String headerAuth = request.getHeader("Authorization");if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) {return headerAuth.substring(7);}return null;}
}

三、前后端交互設計

3.1 登錄接口設計

@RestController
@RequestMapping("/api/auth")
public class AuthController {@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate JwtUtils jwtUtils;@PostMapping("/login")public ResponseEntity<?> authenticateUser(@RequestBody LoginRequest loginRequest) {Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));SecurityContextHolder.getContext().setAuthentication(authentication);String jwt = jwtUtils.generateToken(authentication);UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();return ResponseEntity.ok(new JwtResponse(jwt, userDetails.getId(), userDetails.getUsername(), userDetails.getEmail()));}
}

3.2 前端請求處理

在Vue項目中,我們使用axios進行HTTP請求,并配置請求和響應攔截器:

// 請求攔截器
axios.interceptors.request.use(config => {const token = localStorage.getItem('token');if (token) {config.headers['Authorization'] = 'Bearer ' + token;}return config;},error => {return Promise.reject(error);}
);// 響應攔截器
axios.interceptors.response.use(response => {return response.data;},error => {if (error.response.status === 401) {// 處理token過期或無效的情況localStorage.removeItem('token');router.push('/login');}return Promise.reject(error);}
);

更改后的界面如下:

點擊注銷登錄后恢復原來的登錄界面則大功告成

四、項目實踐中的經驗總結

  1. ??安全性考慮??:

    • 使用HTTPS加密傳輸
    • 設置合理的token過期時間
    • 敏感操作需要二次驗證
    • 密碼必須加密存儲(BCrypt)
  2. ??性能優化??:

    • 減少JWT的payload大小
    • 考慮使用Redis緩存用戶權限信息
    • 實現token刷新機制,避免頻繁登錄
  3. ??異常處理??:

    • 統一的認證異常處理
    • 詳細的錯誤信息返回(但不暴露系統細節)
    • 友好的前端錯誤提示
  4. ??測試要點??:

    • 多種場景測試:正確憑證、錯誤憑證、過期token、無效token
    • 并發請求測試
    • 前后端分離情況下的跨域測試

五、進一步探索方向

  1. ??OAuth2.0集成??:實現第三方登錄功能
  2. ??多因素認證??:增加短信/郵箱驗證碼等二次驗證
  3. ??權限精細化控制??:基于RBAC模型的權限管理
  4. ??單點登錄(SSO)??:多系統間的統一認證
  5. ??安全審計??:記錄用戶登錄日志和敏感操作

結語

通過這個皮膚信息管理系統的登錄認證模塊實現,我深刻理解了Spring Security和JWT的工作原理,掌握了前后端分離架構下的認證流程設計。這些知識不僅適用于當前項目,也為今后開發更復雜的系統打下了堅實基礎。建議初學者可以從這個小而完整的模塊入手,逐步擴展到更復雜的安全場景。

??項目完整代碼已上傳GitHub??:項目地址

歡迎在評論區交流Spring Boot安全實現的相關問題!

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

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

相關文章

【初階數據結構】雙向鏈表

文章目錄 雙向鏈表1.申請節點2.鏈表初始化3.尾插4.打印鏈表5.頭插6.尾刪7.頭刪8.查找9.指定位置插入10.刪除pos節點11.鏈表的銷毀12.程序源碼 雙向鏈表 鏈表分類 8種 (帶頭/不帶頭 單向/雙向 循環/循環) 最常用兩種 單鏈表(不帶頭單向不循環鏈表) 雙向鏈表&#xff08;帶頭雙向…

從 Prompt 管理到人格穩定:探索 Cursor AI 編輯器如何賦能 Prompt 工程與人格風格設計(下)

六、引入 Cursor AI 編輯器的開發流程革新 在整個系統開發過程中&#xff0c;我大量采用了 Cursor 編輯器作為主要的開發環境&#xff0c;并獲得以下關鍵收益&#xff1a; 具備 AI 補全與代碼聯想功能&#xff1a;支持通過內置 Copilot 模型對 Python、FastAPI、YAML、JSON 等…

Spark運行架構

Spark框架的核心是一個計算引擎&#xff0c;整體來說&#xff0c;它采用了標準master-slave的結構 ?如下圖所示&#xff0c;它展示了一個Spark執行時的基本結構&#xff0c;圖形中的Driver表示master&#xff0c;負責管理整個集群中的作業任務調度&#xff0c;圖形中的Executo…

基于未合入PR創建增量patch的git管理方法

目錄前言準備操作步驟精準移植基礎PR到本地分支修改代碼鴻蒙編譯、調試、測試具體編譯指令、測試步驟這里帶過&#xff0c;這不是本文論述重點創建diff文件工作倉庫應用最新patch總結前言 作為程序員&#xff0c;多人協同開發同一個需求是正常的。即使是自己一個人搞需求&…

git真正更新項目

背景 Fetch all remote后flutter代碼都拉下來&#xff0c;都是Android項目應用不上&#xff1b;git–>update project才生效&#xff01;&#xff01;&#xff01;

AI時代如何拓展Web前端開發的邊界

文章目錄 1 從“頁面仔”到“智能體驗構建者”——前端的變與不變2 AI 如何重塑 Web 前端&#xff1a;從開發到用戶體驗的革命2.1 AI 賦能開發效率&#xff1a;前端工程師的“超級外掛”2.1.1 智能代碼輔助與生成2.1.2 自動化測試與 Bug 定位 2.2 AI 提升用戶體驗&#xff0c;構…

chrome webdrive異常處理-session not created falled opening key——仙盟創夢IDE

注冊表錯誤 :EKKOK:chromeinstallerut1 Lgoogle update settings.cc:26b falled opening key .( e\Update\ClientStateMedium 8A69D345-D564-463c-AFF1-A69D9E530F96} to set usagestats 連接超時 disconnected: received Inspector.detached eventfailed to check if windo…

【Java EE初階 --- 多線程(進階)】JUC

樂觀學習&#xff0c;樂觀生活&#xff0c;才能不斷前進啊&#xff01;&#xff01;&#xff01; 我的主頁&#xff1a;optimistic_chen 我的專欄&#xff1a;c語言 &#xff0c;Java 歡迎大家訪問~ 創作不易&#xff0c;大佬們點贊鼓勵下吧~ 文章目錄 JUC組件ReentrantLock與s…

免費靜態網站搭建

免費靜態網站搭建 內容簡介搭建步驟GitHub倉庫創建Jekyll安裝使用Jekyll安裝指南Jekyll快速搭建測試Jekyll后續玩法 內容簡介 &#x1f6a9;Tech Contents&#xff1a;GithubPage/Jekyll/Custom URLs &#x1f431;GitHub Pages&#xff1a;靜態網站托管服務&#xff0c;自動將…

MySQL 8.0 OCP 1Z0-908 題目解析(21)

題目81 Choose two. Examine the modified output: mysql> SHOW SLAVE STATUS\G *************************** 1. row ***************************Slave_IO_Running: YesSlave_SQL_Running: YesSeconds_Behind_Master: 1612Seconds_Behind_Master value is steadily gro…

Web前端開發-HTML、CSS

文章目錄是什么&#xff1f;HTML快速入門VS Code開發工具基礎標簽&樣式新浪新聞-標題標題排版標題樣式標題樣式-1標題樣式-2超鏈接新浪新聞-正文新浪新聞-正文排版新浪新聞-頁面布局表格標簽表單標簽表單標簽-表單項是什么&#xff1f; HTML快速入門 VS Code開發工具 基礎標…

Vue.js狀態管理: Vuex在大型項目中的實際應用

# Vue.js狀態管理: Vuex在大型項目中的實際應用 ## 一、Vuex核心架構與大型項目適配 ### 1.1 狀態管理&#xff08;State Management&#xff09;的本質需求 在復雜前端系統中&#xff0c;組件間的數據傳遞成本隨項目規模呈指數級增長。根據Vue官方統計&#xff0c;超過500個組…

C++開發:結構體作為函數形參的值傳遞與引用傳遞

筆者定義了一個結構體變量&#xff0c;用于作為函數的形參&#xff0c;定義如下&#xff1a;struct CardParameters {float* Average nullptr;int averageSize 0; }; 需求描述&#xff1a;結構體變量作為函數的形參&#xff0c;在函數體中給指針變量分配內存空間并賦值&#…

【unity小技巧】在 Unity 中將 2D 精靈添加到 3D 游戲中,并實現陰影投射效果,實現類《八分旅人》《饑荒》等等的2.5D游戲效果

注意&#xff1a;考慮到unity小技巧的內容比較多&#xff0c;我將該內容分開&#xff0c;并全部整合放在【unity小技巧】專欄里&#xff0c;感興趣的小伙伴可以前往逐一查看學習。 文章目錄 前言實戰1、在3D場景中&#xff0c;新建一些不同形狀的2D圖片2、我們新建一個Lit材質3…

Rust 內存結構:深入解析

Rust 的內存管理系統是其核心特性之一&#xff0c;結合了手動內存管理的效率與自動內存管理的安全性。以下是 Rust 內存結構的全面解析&#xff1a; 內存布局概覽 ----------------------- | 代碼段 (Text) | 只讀&#xff0c;存儲可執行指令 ----------------------…

【Chrome】‘Good助手‘ 擴展程序使用介紹

這是我開發的一款 Chrome 瀏覽器擴展程序&#xff0c;目前主要集成了‘AI對話‘&#xff0c;’總結頁面’&#xff0c;‘基于頁面問答’等功能&#xff0c;最近幾天我也將寫一篇介紹如何開發 chrome 擴展程序的博客&#xff0c;帶你了解如何開發屬于自己的插件。 注&#xff1…

基于mysql8.0.27部署1主2從的MHA集群

目錄 一、mysql概述 1.1、關系型數據庫 1.2、MySQL數據庫 1.3、RDBMS術語 二、mysql的部署 2.1、拉取mysql 2.2、解壓 2.3、 改名 2.4、 指定安裝文件位置 2.5、 創建用戶組 2.6、 修改mysql配置文件 2.7、創建data文件夾 2.8、更改mysql目錄權限 2.9、初始化數據…

Highcharts 安裝使用教程

一、Highcharts 簡介 Highcharts 是一款使用 JavaScript 編寫的前端數據可視化庫&#xff0c;支持折線圖、柱狀圖、餅圖、面積圖、散點圖等多種圖表類型&#xff0c;特點是渲染性能優秀、交互豐富、兼容性強&#xff0c;適合構建商業圖表、統計報表等。 二、Highcharts 安裝方…

Qt中的坐標系

Qt中的坐標系 1.坐標系概念2.數學坐標系VS計算機坐標系3.Qt坐標系4.像素 &#x1f31f;&#x1f31f;hello&#xff0c;各位讀者大大們你們好呀&#x1f31f;&#x1f31f; &#x1f680;&#x1f680;系列專欄&#xff1a;【Qt的學習】 &#x1f4dd;&#x1f4dd;本篇內容&am…

C++原子類型操作與內存序

C原子類型操作與內存序詳解 這段內容深入介紹了C標準原子類型的操作接口、內存序語義及使用規范。以下是關鍵知識點的分層解析&#xff1a; 一、原子類型的命名規則與類型映射 C提供兩種方式表示原子類型&#xff1a; 模板特化形式&#xff1a;std::atomic<T>別名形式…