SpringBoot實(shí)現(xiàn)不同用戶不同訪問權(quán)限的示例代碼
前提
近期在使用 Spring Boot,用戶角色被分為管理者和普通用戶;角色不同,權(quán)限也就存在不同。
在 Spring Boot 里實(shí)現(xiàn)不同用戶擁有不同訪問權(quán)限,可借助 Spring Security 框架達(dá)成。
實(shí)現(xiàn)
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. 數(shù)據(jù)庫表設(shè)計(jì)
創(chuàng)建三張表,分別是用戶表、角色表以及用戶角色關(guān)聯(lián)表:
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. 實(shí)體類設(shè)計(jì)
創(chuàng)建與數(shù)據(jù)庫表對應(yīng)的實(shí)體類:
// 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. 創(chuàng)建 Repository 接口
為 User 和 Role 分別創(chuàng)建 Repository 接口,用于數(shù)據(jù)訪問:
// 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. 實(shí)現(xiàn) UserDetailsService
實(shí)現(xiàn) Spring Security 的 UserDetailsService 接口,從數(shù)據(jù)庫加載用戶信息:
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;
}
@Override
public 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 進(jìn)行配置,設(shè)置不同 URL 的訪問權(quán)限:
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 {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public 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. 創(chuàng)建控制器
創(chuàng)建不同權(quán)限的控制器示例:
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. 測試用戶數(shù)據(jù)
創(chuàng)建測試用戶數(shù)據(jù),以便進(jìn)行測試:
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 {
@Autowired
private UserRepository userRepository;
@Autowired
private RoleRepository roleRepository;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public void run(String... args) throws Exception {
// 創(chuàng)建角色
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);
}
// 創(chuàng)建管理員用戶
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);
}
// 創(chuàng)建普通用戶
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);
}
}
}
權(quán)限控制說明
@PreAuthorize 注解:能在方法級別進(jìn)行權(quán)限控制。例如:
@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/admin/hello")
public String adminHello() {
return "Admin Hello!";
}
角色繼承:可以讓 ADMIN 角色繼承 USER 角色的權(quán)限,配置如下:
@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;
}
到此這篇關(guān)于SpringBoot實(shí)現(xiàn)不同用戶不同訪問權(quán)限的示例代碼的文章就介紹到這了,更多相關(guān)SpringBoot不同用戶不同訪問權(quán)限內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringCloud Ribbon 負(fù)載均衡的實(shí)現(xiàn)
Ribbon是一個(gè)客戶端負(fù)載均衡器,它提供了對HTTP和TCP客戶端的行為的大量控制。這篇文章主要介紹了SpringCloud Ribbon 負(fù)載均衡的實(shí)現(xiàn),感興趣的小伙伴們可以參考一下2019-01-01
在SpringBoot中更改默認(rèn)端口的方法總結(jié)
在本文中,小編將帶大家學(xué)習(xí)如何在 Spring Boot 中更改默認(rèn)端口,默認(rèn)情況下,嵌入式 Web 服務(wù)器使用 8080端口來啟動 Spring 引導(dǎo)應(yīng)用程序,有幾種方法可以更改該端口,文中介紹的非常詳細(xì),需要的朋友可以參考下2023-07-07
如何創(chuàng)建SpringBoot項(xiàng)目
這篇文章主要介紹了如何創(chuàng)建SpringBoot項(xiàng)目,幫助大家更好的學(xué)習(xí)和使用springboot框架,感興趣的朋友可以了解下2021-01-01
Java多線程中的wait/notify通信模式實(shí)例詳解
這篇文章主要給大家介紹了關(guān)于Java多線程中wait/notify通信模式的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
MyBatis-Plus 自動填充的實(shí)現(xiàn)示例
MyBatis-Plus 提供了自動填充功能,幫助開發(fā)者在插入或更新數(shù)據(jù)時(shí),自動為某些字段賦值,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-09-09
java實(shí)現(xiàn)日歷應(yīng)用程序設(shè)計(jì)
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)日歷應(yīng)用程序設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06
spring security中的csrf防御原理(跨域請求偽造)
這篇文章主要介紹了spring security中的csrf防御機(jī)制原理解析(跨域請求偽造),本文通過實(shí)例代碼詳解的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-12-12
spring boot 1.5.4 集成shiro+cas,實(shí)現(xiàn)單點(diǎn)登錄和權(quán)限控制
這篇文章主要介紹了spring boot 1.5.4 集成shiro+cas,實(shí)現(xiàn)單點(diǎn)登錄和權(quán)限控制,需要的朋友可以參考下2017-06-06

