Spring Boot 實現不同用戶不同訪問權限

前提

近期在使用 Spring Boot,用戶角色被分為管理者和普通用戶;角色不同,權限也就存在不同。

在 Spring Boot 里實現不同用戶擁有不同訪問權限,可借助 Spring Security 框架達成。

實現

1. 添加必要依賴

首先要在 pom.xml 里添加 Spring Security 和 JPA 的依賴。

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency>
</dependencies>

2. 數據庫表設計

創建三張表,分別是用戶表、角色表以及用戶角色關聯表:

CREATE TABLE users (id INT PRIMARY KEY AUTO_INCREMENT,username VARCHAR(50) NOT NULL UNIQUE,password VARCHAR(100) NOT NULL,enabled BOOLEAN DEFAULT true
);CREATE TABLE roles (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(50) NOT NULL UNIQUE
);CREATE TABLE user_roles (user_id INT NOT NULL,role_id INT NOT NULL,PRIMARY KEY (user_id, role_id),FOREIGN KEY (user_id) REFERENCES users(id),FOREIGN KEY (role_id) REFERENCES roles(id)
);

3. 實體類設計

創建與數據庫表對應的實體類:

// User.java
import javax.persistence.*;
import java.util.Set;@Entity
@Table(name = "users")
public class User {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String username;private String password;private boolean enabled;@ManyToMany(fetch = FetchType.EAGER)@JoinTable(name = "user_roles",joinColumns = @JoinColumn(name = "user_id"),inverseJoinColumns = @JoinColumn(name = "role_id"))private Set<Role> roles;// getters and setters
}// Role.java
import javax.persistence.*;@Entity
@Table(name = "roles")
public class Role {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String name;// getters and setters
}

4. 創建 Repository 接口

為 User 和 Role 分別創建 Repository 接口,用于數據訪問:

// UserRepository.java
import org.springframework.data.jpa.repository.JpaRepository;public interface UserRepository extends JpaRepository<User, Long> {User findByUsername(String username);
}// RoleRepository.java
import org.springframework.data.jpa.repository.JpaRepository;public interface RoleRepository extends JpaRepository<Role, Long> {Role findByName(String name);
}

5. 實現 UserDetailsService

實現 Spring Security 的 UserDetailsService 接口,從數據庫加載用戶信息:

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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;
import java.util.List;
import java.util.Set;@Service
public class CustomUserDetailsService implements UserDetailsService {private final UserRepository userRepository;public CustomUserDetailsService(UserRepository userRepository) {this.userRepository = userRepository;}@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {User user = userRepository.findByUsername(username);if (user == null) {throw new UsernameNotFoundException("User not found with username: " + username);}return new org.springframework.security.core.userdetails.User(user.getUsername(),user.getPassword(),user.isEnabled(),true,true,true,getAuthorities(user.getRoles()));}private List<GrantedAuthority> getAuthorities(Set<Role> roles) {List<GrantedAuthority> authorities = new ArrayList<>();for (Role role : roles) {authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getName()));}return authorities;}
}

6. 配置 Spring Security

對 Spring Security 進行配置,設置不同 URL 的訪問權限:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;@Configuration
@EnableWebSecurity
public class SecurityConfig {@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/public/**").permitAll().antMatchers("/admin/**").hasRole("ADMIN").antMatchers("/user/**").hasAnyRole("USER", "ADMIN").anyRequest().authenticated().and().formLogin().loginPage("/login").permitAll().and().logout().permitAll();return http.build();}
}

7. 創建控制器

創建不同權限的控制器示例:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class HelloController {@GetMapping("/public/hello")public String publicHello() {return "Public Hello!";}@GetMapping("/user/hello")public String userHello() {return "User Hello!";}@GetMapping("/admin/hello")public String adminHello() {return "Admin Hello!";}
}

8. 測試用戶數據

創建測試用戶數據,以便進行測試:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;import java.util.Collections;
import java.util.HashSet;@Component
public class DataInitializer implements CommandLineRunner {@Autowiredprivate UserRepository userRepository;@Autowiredprivate RoleRepository roleRepository;@Autowiredprivate PasswordEncoder passwordEncoder;@Overridepublic void run(String... args) throws Exception {// 創建角色Role adminRole = roleRepository.findByName("ADMIN");if (adminRole == null) {adminRole = new Role();adminRole.setName("ADMIN");roleRepository.save(adminRole);}Role userRole = roleRepository.findByName("USER");if (userRole == null) {userRole = new Role();userRole.setName("USER");roleRepository.save(userRole);}// 創建管理員用戶User adminUser = userRepository.findByUsername("admin");if (adminUser == null) {adminUser = new User();adminUser.setUsername("admin");adminUser.setPassword(passwordEncoder.encode("admin123"));adminUser.setEnabled(true);adminUser.setRoles(new HashSet<>(Collections.singletonList(adminRole)));userRepository.save(adminUser);}// 創建普通用戶User normalUser = userRepository.findByUsername("user");if (normalUser == null) {normalUser = new User();normalUser.setUsername("user");normalUser.setPassword(passwordEncoder.encode("user123"));normalUser.setEnabled(true);normalUser.setRoles(new HashSet<>(Collections.singletonList(userRole)));userRepository.save(normalUser);}}
}

權限控制說明

  • @PreAuthorize 注解:能在方法級別進行權限控制。例如:
    @PreAuthorize("hasRole('ADMIN')")
    @GetMapping("/admin/hello")
    public String adminHello() {return "Admin Hello!";
    }
    
  • 角色繼承:可以讓 ADMIN 角色繼承 USER 角色的權限,配置如下:
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/public/**").permitAll().antMatchers("/user/**").hasRole("USER").antMatchers("/admin/**").hasRole("ADMIN").anyRequest().authenticated().and().roleHierarchy(roleHierarchy());return http.build();
    }@Bean
    public RoleHierarchy roleHierarchy() {RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER");return roleHierarchy;
    }
    

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

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

相關文章

華沿協作機器人:數字孿生技術賦能焊接領域智能化升級

在工業4.0與智能制造浪潮的推動下&#xff0c;焊接行業正經歷從傳統工藝向數字化、柔性化轉型的關鍵階段。作為國內協作機器人領域的創新者&#xff0c;華沿機器人通過融合數字孿生、智能感知與多軸協同技術&#xff0c;在焊接場景中實現了技術突破與應用創新。本文將從技術原理…

Linux中部署Nacos保姆級教程

前置說明&#xff1a; Dokcer部署Nacos官方文檔&#xff1a;Nacos Docker 快速開始 | Nacos 官網 一、Nacos版本說明 Nacos 1.x 版本 Nacos 1.1.3 &#xff1a;是一個相對穩定的版本&#xff0c;在一段時期內被廣泛使用&#xff0c;但目前該版本已經下線&#xff0c;不再單獨維…

戰神授權后臺報錯:Parse error: syntax error, unexpected end of file in解決辦法

問題現象分析 當您在戰神授權后臺遇到"Parse error: syntax error, unexpected end of file"這個錯誤時&#xff0c;說明PHP解析器在解析腳本文件時遇到了意外結束的情況。這種錯誤通常發生在PHP代碼結構不完整時&#xff0c;比如缺少閉合的大括號、分號或者PHP結束…

HTML<span>元素詳解

HTML<span>元素詳解 <span> 是 HTML 中最常用的內聯(inline)容器元素&#xff0c;用于對文檔中的部分文本或內容進行標記和樣式化。 一、基本語法 <span>內容</span>二、主要特點 內聯元素&#xff1a;不會獨占一行&#xff0c;只占據內容所需寬度無…

vscode ssh遠程連接到Linux并實現免密碼登錄

vscode ssh遠程連接到Linux并實現免密碼登錄 文章目錄 vscode ssh遠程連接到Linux并實現免密碼登錄一、安裝VSCode擴展二、Linux側工作三、連接四、實現免密登錄 一、安裝VSCode擴展 擴展一欄搜索remote找到Remote Development插件直接點擊Install安裝即可 二、Linux側工作 U…

超級詳細 的 Apache Camel 教程

前言 通過本教程學習 Apache Camel 的基礎知識并在 Spring Boot 項目上創建您的第一個 Camel。 想開始使用Apache Camel嗎&#xff1f;這是我關于這個流行的 Java 集成框架的教程。 我為完整的初學者編寫了這個 Apache Camel 教程。它向您介紹了 Camel 的核心概念&#xff0c;并…

使用GithubActions和騰訊CloudBase自動發布靜態網頁

騰訊 CloudBase 可以用于托管靜態網站&#xff0c;服務開通之后&#xff0c;使用 CloudBase CLI 可以將本地靜態網站上傳到 CloudBase&#xff0c;并生成相應的訪問域名。 配置 Workflow 創建 .github/workflows/deploy.yml 文件, 編輯內容如下&#xff1a; name: Deploy to…

《聊一聊ZXDoc》之汽車標定、臺架標定、三高標定

ZXDoc支持XCP/CCP標定功能&#xff0c;標定工作貫穿主機廠與Tier1廠商汽車ECU研發、生產、測試的整個流程&#xff0c;是保障ECU性能達標、功能穩定的關鍵。 什么是XCP/CCP標定&#xff1f; XCP/CCP標定是汽車電子領域用于ECU標定和測量的核心通信協議&#xff0c;由ASAM組織…

【目標檢測】評估指標詳解:Precision/Recall/F1-Score

&#x1f9d1; 博主簡介&#xff1a;曾任某智慧城市類企業算法總監&#xff0c;目前在美國市場的物流公司從事高級算法工程師一職&#xff0c;深耕人工智能領域&#xff0c;精通python數據挖掘、可視化、機器學習等&#xff0c;發表過AI相關的專利并多次在AI類比賽中獲獎。CSDN…

【unity游戲開發——網絡】網絡協議、TCP vs UDP 本質區別

注意&#xff1a;考慮到熱更新的內容比較多&#xff0c;我將熱更新的內容分開&#xff0c;并全部整合放在【unity游戲開發——網絡】專欄里&#xff0c;感興趣的小伙伴可以前往逐一查看學習。 文章目錄 一、網絡協議概述二、OSI七層模型三、TCP/IP四層模型四、核心傳輸協議對比…

Spark Streaming 與 Flink 實時數據處理方案對比與選型指南

Spark Streaming 與 Flink 實時數據處理方案對比與選型指南 實時數據處理在互聯網、電商、物流、金融等領域均有大量應用&#xff0c;面對海量流式數據&#xff0c;Spark Streaming 和 Flink 成為兩大主流開源引擎。本文基于生產環境需求&#xff0c;從整體架構、編程模型、容…

鴻蒙HarmonyOS 5小游戲實踐:記憶翻牌(附:源代碼)

記憶翻牌游戲是一款經典的益智游戲&#xff0c;它能有效鍛煉玩家的記憶力和觀察能力。本文將詳細介紹如何使用鴻蒙&#xff08;HarmonyOS&#xff09;的ArkUI框架開發一款完整的記憶翻牌游戲&#xff0c;涵蓋游戲設計、核心邏輯實現和界面構建的全過程。 游戲設計概述 記憶翻牌…

【Linux庖丁解牛】— 文件系統!

1 引?"塊"概念 其實硬盤是典型的“塊”設備&#xff0c;操作系統讀取硬盤數據的時候&#xff0c;其實是不會?個個扇區地讀取&#xff0c;這樣 效率太低&#xff0c;?是?次性連續讀取多個扇區&#xff0c;即?次性讀取?個”塊”&#xff08;block&#xff09;。…

如何通過自動化減少重復性工作

通過自動化減少重復性工作的關鍵策略包括&#xff1a;1、識別可被規則化操作的任務、2、引入RPA&#xff08;機器人流程自動化&#xff09;工具、3、整合AI與業務流程系統、4、部署腳本與低代碼平臺、5、持續優化自動化場景與效率。 其中&#xff0c;“引入RPA工具”被廣泛認為…

知識變現全鏈路設計:從IP打造到商業閉環的系統方法論|創客匠人

一、變現低效根源&#xff1a;碎片化努力為何換不來持續增長&#xff1f; 創客匠人服務上千位知識創業者后發現&#xff0c;變現乏力多因缺乏系統設計&#xff1a;某營銷專家的課程因定位模糊、表達生硬、渠道單一&#xff0c;低價仍少有人問。文檔中提出的“六大超級設計公式…

如何利用人工智能大模型提升流量質量

摘要 流量質量是衡量數字化營銷效果的重要指標之一&#xff0c;它反映了用戶對網站或應用的興趣和滿意度。流量質量的常用評估方法有點擊率、跳出率和用戶停留時間等。本文將介紹如何利用人工智能大模型來分析和優化這些指標&#xff0c;提高流量質量&#xff0c;從而提升數字…

從單體架構到微服務:微服務架構演進與實踐

一、單體架構的困境與演進 &#xff08;一&#xff09;單體應用的初始優勢與演進路徑 在系統發展的初期&#xff0c;單體架構憑借其簡單性和開發效率成為首選。單體應用將整個系統的所有功能模塊整合在一個項目中&#xff0c;以單一進程的方式運行&#xff0c;特別適合小型系…

Elasticsearch 自定義排序:使用 Painless 腳本實現復雜排序邏輯

需求背景&#xff1a; 從es查詢數據出來的時候&#xff0c;要求type為CATALOG的數據排在最前面&#xff0c;也就是目錄類型的要放在最前面&#xff0c;而且要求按照層級排序&#xff0c;從L1到L5順序排序 直接上解法&#xff1a; {//查詢條件"query": {"bool…

華為云Flexus+DeepSeek征文|華為云數字人 + DeepSeek:智能交互的革命性突破

目錄 前言 關于華為云數字人和云服務 1、華為云數字人 &#xff08;1&#xff09;MetaStudio介紹 &#xff08;2&#xff09;應用場景 &#xff08;3&#xff09;功能特性 &#xff08;4&#xff09;使用體驗 2、華為云云服務 華為云數字人結合DeepSeek的核心流程 1、…

【GESP】C++四級練習 luogu-P5729 【深基5.例7】工藝品制作

GESP C四級練習&#xff0c;二維/多維數組練習&#xff0c;難度★★☆☆☆。 題目題解詳見&#xff1a;【GESP】C四級練習 luogu-P5729 【深基5.例7】工藝品制作 | OneCoder 【GESP】C四級練習 luogu-P5729 【深基5.例7】工藝品制作 | OneCoderGESP C四級練習&#xff0c;二維…