使用Spring Boot與Spring Security構建安全的RESTful API

使用Spring Boot與Spring Security構建安全的RESTful API

引言

在現代Web應用開發中,安全性是一個不可忽視的重要方面。Spring Boot和Spring Security為開發者提供了一套強大的工具,用于構建安全的RESTful API。本文將詳細介紹如何結合Spring Boot和Spring Security,并集成JWT(JSON Web Token)實現身份驗證與授權。

技術棧

  • 核心框架: Spring Boot, Spring Security
  • 身份驗證: JWT
  • 數據庫: H2(示例用)
  • 構建工具: Maven

項目初始化

首先,我們需要創建一個Spring Boot項目。可以通過Spring Initializr(https://start.spring.io/)快速生成項目骨架。選擇以下依賴:

  • Spring Web
  • Spring Security
  • H2 Database
  • Lombok(可選,簡化代碼)

配置Spring Security

Spring Security默認會為所有端點啟用基本認證。我們需要自定義配置以實現JWT認證。

1. 添加JWT依賴

pom.xml中添加以下依賴:

<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId><version>0.11.5</version>
</dependency>
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-impl</artifactId><version>0.11.5</version><scope>runtime</scope>
</dependency>
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-jackson</artifactId><version>0.11.5</version><scope>runtime</scope>
</dependency>

2. 創建JWT工具類

編寫一個工具類用于生成和驗證JWT:

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;@Component
public class JwtTokenUtil {private String secret = "your-secret-key";public String generateToken(UserDetails userDetails) {Map<String, Object> claims = new HashMap<>();return createToken(claims, userDetails.getUsername());}private String createToken(Map<String, Object> claims, String subject) {return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis())).setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) // 10小時有效期.signWith(SignatureAlgorithm.HS256, secret).compact();}public Boolean validateToken(String token, UserDetails userDetails) {final String username = extractUsername(token);return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));}private Boolean isTokenExpired(String token) {return extractExpiration(token).before(new Date());}public String extractUsername(String token) {return extractClaim(token, Claims::getSubject);}public Date extractExpiration(String token) {return extractClaim(token, Claims::getExpiration);}private <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {final Claims claims = extractAllClaims(token);return claimsResolver.apply(claims);}private Claims extractAllClaims(String token) {return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();}
}

3. 配置Security Filter

創建一個過濾器,用于攔截請求并驗證JWT:

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@Component
public class JwtRequestFilter extends OncePerRequestFilter {private final JwtTokenUtil jwtTokenUtil;private final UserDetailsServiceImpl userDetailsService;public JwtRequestFilter(JwtTokenUtil jwtTokenUtil, UserDetailsServiceImpl userDetailsService) {this.jwtTokenUtil = jwtTokenUtil;this.userDetailsService = userDetailsService;}@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throws ServletException, IOException {final String authorizationHeader = request.getHeader("Authorization");String username = null;String jwt = null;if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {jwt = authorizationHeader.substring(7);username = jwtTokenUtil.extractUsername(jwt);}if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);if (jwtTokenUtil.validateToken(jwt, userDetails)) {UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);}}chain.doFilter(request, response);}
}

4. 配置Spring Security

SecurityConfig類中配置Spring Security:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {private final UserDetailsServiceImpl userDetailsService;private final JwtRequestFilter jwtRequestFilter;public SecurityConfig(UserDetailsServiceImpl userDetailsService, JwtRequestFilter jwtRequestFilter) {this.userDetailsService = userDetailsService;this.jwtRequestFilter = jwtRequestFilter;}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Override@Beanpublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/authenticate").permitAll().anyRequest().authenticated().and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);}
}

實現認證與授權

1. 創建用戶服務

實現UserDetailsService接口,用于加載用戶信息:

import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;import java.util.ArrayList;@Service
public class UserDetailsServiceImpl implements UserDetailsService {@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {// 實際項目中應從數據庫加載用戶信息return new User("admin", "$2a$10$slYQmyNdGzTn7ZLBXBChFOC9f6kFjAqPhccnP6DxlWXx2lPk1C3G6", new ArrayList<>());}
}

2. 創建認證接口

創建一個控制器用于生成JWT:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;@RestController
public class AuthenticationController {@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate UserDetailsServiceImpl userDetailsService;@Autowiredprivate JwtTokenUtil jwtTokenUtil;@PostMapping("/authenticate")public ResponseEntity<?> createAuthenticationToken(@RequestBody AuthenticationRequest authenticationRequest) {authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(),authenticationRequest.getPassword()));final UserDetails userDetails = userDetailsService.loadUserByUsername(authenticationRequest.getUsername());final String jwt = jwtTokenUtil.generateToken(userDetails);return ResponseEntity.ok(new AuthenticationResponse(jwt));}
}

測試API

使用Postman或curl測試以下端點:

  1. 獲取JWT

    POST /authenticate
    {"username": "admin","password": "password"
    }
    
  2. 訪問受保護資源

    GET /api/protected
    Headers: Authorization: Bearer <your-jwt-token>
    

總結

本文詳細介紹了如何使用Spring Boot和Spring Security構建安全的RESTful API,并集成JWT實現身份驗證與授權。通過實際代碼示例,開發者可以快速掌握相關技術。

擴展閱讀

  • Spring Security官方文檔
  • JWT官方文檔
  • Spring Boot官方文檔

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

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

相關文章

機器人拖動示教控制

機器人拖動示教控制 機器人拖動視角控制與軌跡記錄 1. 知識目標 體驗ES機器人拖動視角操作體驗ES機器人拖動軌跡記錄 2. 技能目標 掌握ES機器人拖動視角操作掌握ES機器人拖動軌跡記錄 3. ES機器人拖動視角操作 3.1 操作步驟 點擊“拖動視角”按鈕長按“啟用”鍵約3秒進入…

RuoYi-Vue3-FastAPI框架的功能實現(上)

RuoYi-Vue3-FastAPI框架的功能實現&#xff08;上&#xff09; 感謝大佬給出關于python后端的若依框架&#xff0c;希望這個簡單文檔能幫助到大家。 安裝與運行&#xff1a; 下載地址&#xff1a;Vue2版本&#xff1a; Gitte倉庫地址&#xff1a;RuoYi-Vue-FastAPI: 基于Vu…

Paimon和Hive相集成

Paimon版本1.17 Hive版本3.1.3 1、Paimon集成Hive 將paimon-hive-connector.jar復制到auxlib中&#xff0c;下載鏈接Index of /groups/snapshots/org/apache/https://repository.apache.org/snapshots/org/apache/paimon/ 通過flink進入查看paimon /opt/softwares/flink-1…

【Leetcode 每日一題】3362. 零數組變換 III

問題背景 給你一個長度為 n n n 的整數數組 n u m s nums nums 和一個二維數組 q u e r i e s queries queries&#xff0c;其中 q u e r i e s [ i ] [ l i , r i ] queries[i] [l_i, r_i] queries[i][li?,ri?]。 每一個 q u e r i e s [ i ] queries[i] queries[i]…

計算機視覺與深度學習 | 用于圖像分割的自監督學習(Self-Supervised Learning)方法綜述

圖像分割 用于圖像分割的自監督學習(Self-Supervised Learning)方法綜述**1. 背景與意義****2. 方法演進****3. 圖像分割子任務與SSL策略****4. 自監督預訓練任務分類****5. 基準數據集與評估指標****6. 挑戰與未來方向****總結**用于圖像分割的自監督學習(Self-Supervised …

Jenkins集成Docker與K8S構建

Jenkins 是一個開源的持續集成和持續交付(CI/CD)工具,廣泛用于自動化軟件開發過程中的構建、測試和部署任務。它通過插件系統提供了高度的可擴展性,支持與多種開發工具和技術的集成。 Jenkins 的核心功能 Jenkins 的主要功能包括自動化構建、測試和部署。它能夠監控版本控…

使用 adb 命令截取 Android 設備的屏幕截圖

使用 adb 命令截取 Android 設備的屏幕截圖。以下是兩種常見的方法&#xff1a; 方法一&#xff1a;截屏后保存到電腦 adb shell screencap -p /sdcard/screenshot.png adb pull /sdcard/screenshot.png解釋&#xff1a; adb shell screencap -p /sdcard/screenshot.png&…

參與開發的注意事項

1.開發期間&#xff0c;不要擅自修改架構的內容 使用技術官發的項目文件夾來開發&#xff0c;而不是自己建立項目&#xff0c; 否則會導致環境不統一 架構內容&#xff1a;&#xff08;不能更改&#xff09; 1.類型定義&#xff0c;全局變量聲明 2.函數申明&#xff08;函數名稱…

linux安裝nginx和前端部署vue項目

1、打包前端項目 npm run build 執行完后會在根目錄下生成一個dist文件夾&#xff0c;這個dist文件夾就是我們后面要部署到nginx的東西。 2、將dist文件夾上傳到服務器中 自己建一個目錄&#xff0c;上傳即可&#xff08;盡量不要在root目錄下&#xff0c;可能涉及權限問題…

親測有效!OGG 創建抽取進程報錯 OGG-08241,如何解決?

前言 今天在測試 OGG 一個功能的時候&#xff0c;需要重新初始化 oggca&#xff0c;所以重裝了一下 OGG。重建完之后重新添加抽取進程報錯&#xff0c;一直無法添加成功&#xff1a; 經過一翻分析&#xff0c;找到了解決方案&#xff0c;本文記錄一下解決過程。 問題描述 OG…

Docker構建 Dify 應用定時任務助手

概述 Dify 定時任務管理工具是一個基于 GitHub Actions 的自動化解決方案&#xff0c;用于實現 Dify Workflow 的定時執行和狀態監控。無需再為缺乏定時任務支持而感到困擾&#xff0c;本工具可以幫助設置自動執行任務并獲取實時通知&#xff0c;優化你的工作效率。 注意&…

ubuntu24.04+RTX5090D 顯卡驅動安裝

初步準備 Ubuntu默認內核太舊&#xff0c;用mainline工具安裝新版&#xff1a; sudo add-apt-repository ppa:cappelikan/ppa sudo apt update && sudo apt full-upgrade sudo apt install -y mainline mainline list # 查看可用內核列表 mainline install 6.13 # 安裝…

網絡爬蟲(Web Crawler)詳解

網絡爬蟲(Web Crawler)詳解 1. 基本概念與核心目標 定義: 網絡爬蟲是一種自動化的程序,通過HTTP協議訪問網頁,提取并存儲數據(如文本、鏈接、圖片),并根據策略遞歸訪問新鏈接。核心目標: 數據采集:抓取特定網站或全網公開數據。索引構建:為搜索引擎提供頁面內容(如…

大模型如何助力數學可視化?

大家好&#xff0c;我是 i 學習的老章 在數學學習和教學中&#xff0c;將抽象概念可視化對于理解至關重要。Manim 是一個強大的數學動畫引擎&#xff0c;由著名數學科普視頻作者 3Blue1Brown 開發并廣為人知。 老章較早之前就介紹過 manim&#xff1a;B 站上爆紅的數學視頻&a…

Oracle基礎知識(二)

目錄 1.聚合函數 2.COUNT(1)&COUNT(*)&COUNT(字段)區別&#xff08;面試常問&#xff09; 3.分組聚合——group by 4.去重&#xff1a;DISTINCT 、GROUP BY 5.聚合函數的過濾HAVING 6.oracle中having與where的區別 (面試常問) 7.ROUND與TRUNC函數 8.ROLLUP上卷…

DTAS 3D多約束裝配助力懸架公差分析尺寸鏈計算:麥弗遜/雙叉臂/多連桿/H臂一網打盡

摘要&#xff1a;汽車四輪定位參數與懸架密切相關。汽車懸架對于車輛的行駛性能、安全性和舒適性至關重要。DTAS 3D提供了各類型懸架的公差仿真分析方法。 關鍵字&#xff1a;DTAS 3D、前后懸架、公差仿真分析、 運動耦合 一、懸架公差分析綜述 懸架是車身&#xff08;或車架…

Serverless爬蟲架構揭秘:動態IP、冷啟動與成本優化

一、問題背景&#xff1a;舊技術的瓶頸 在傳統爬蟲架構中&#xff0c;我們通常部署任務在本地機器或虛擬機中&#xff0c;搭配定時器調度任務。雖然這種方式簡單&#xff0c;但存在以下明顯缺陷&#xff1a; 固定IP易被封禁&#xff1a;目標網站如拼多多會通過IP頻率監控限制…

設備預測性維護的停機時間革命:中訊燭龍如何用AI重構工業設備管理范式

在工業4.0的智能化浪潮中&#xff0c;非計劃停機每年吞噬企業3%-8%的產值。中訊燭龍預測性維護系統通過多模態感知矩陣分布式智能體的創新架構&#xff0c;實現設備健康管理的范式躍遷&#xff0c;幫助制造企業將停機時間壓縮70%以上。本文將深度解析技術實現路徑與行業級實踐方…

Java面試攻略:從Spring Boot到微服務架構的深入探討

Java面試攻略&#xff1a;從Spring Boot到微服務架構的深入探討 場景設定 在一家知名互聯網大廠的會議室里&#xff0c;資深面試官王老師正在對一位求職者謝飛機進行技術面試。謝飛機是一位幽默風趣的程序員&#xff0c;他的回答有時讓人捧腹大笑。 第一輪&#xff1a;核心技…

LlamaIndex

1、大語言模型開發框架的價值是什么? SDK:Software Development Kit,它是一組軟件工具和資源的集合,旨在幫助開發者創建、測試、部署和維護應用程序或軟件。 所有開發框架(SDK)的核心價值,都是降低開發、維護成本。 大語言模型開發框架的價值,是讓開發者可以更方便地…