更多SpringBoot3内容请关注我的专栏:《SpringBoot3》
期待您的点赞👍收藏⭐评论✍
重学SpringBoot3-集成Spring Security(四)
在现代应用开发中,安全性和数据管理是两大重要模块。Spring Security 提供了全面的安全解决方案,而 Spring Data JPA 则简化了与数据库的交互。将两者结合,可以在保护应用的同时,轻松实现基于用户身份的访问控制、权限管理和安全的数据存储操作。
这篇博客将介绍如何在 Spring Boot 3 项目中,整合 Spring Security 和 Spring Data JPA,以实现用户认证和基于数据库的授权机制。
1. 创建项目
1.1 项目依赖
在 Spring Boot 3 项目中,首先要添加相关的依赖。你可以在
pom.xml
文件中引入以下 Maven 依赖:
<dependencies><!-- Spring Boot Starter for Web Applications --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Spring Security for Authentication and Authorization --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><!-- Spring Data JPA for Database Access --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><!-- MySQL Database for Testing --><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency><!--for bean --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency></dependencies>
这些依赖包括了 Spring Web、Spring Security 和 Spring Data JPA,能够满足创建一个基本的安全和数据库集成的应用。
1.2 创建配置文件
可以参考之前的文章《重学SpringBoot3-Spring Data JPA》,进行Spring Data JPA 的配置:
spring:application:name: spring-boot3-13-security
datasource:url: jdbc:mysql://localhost:3306/spring_security?useSSL=false&serverTimezone=UTCusername: root
password: root123
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:database-platform: org.hibernate.dialect.MySQL5Dialect # 指定Hibernate使用的数据库方言为MySQL 5.x。generateDdl:true# 自动更新数据库表结构show-sql:true# 是否显示 SQL 语句
2. 数据库模型
假设我们有一个 User 实体,其中包含用户的登录信息和角色信息。使用 Spring Data JPA 来定义这个实体类:
packagecom.coderjia.boot313security.bean;importjakarta.persistence.CascadeType;importjakarta.persistence.Column;importjakarta.persistence.Entity;importjakarta.persistence.FetchType;importjakarta.persistence.GeneratedValue;importjakarta.persistence.GenerationType;importjakarta.persistence.Id;importjakarta.persistence.JoinColumn;importjakarta.persistence.JoinTable;importjakarta.persistence.ManyToMany;importjakarta.persistence.Table;importlombok.Data;importjava.util.HashSet;importjava.util.Set;/**
* @author CoderJia
* @create 2024/10/19 下午 04:12
* @Description
**/@Data@Entity@Table(name ="users")publicclassUser{@Id@GeneratedValue(strategy =GenerationType.IDENTITY)privateLong id;@Column(unique =true)privateString username;privateString password;@ManyToMany(fetch =FetchType.EAGER, cascade =CascadeType.ALL)@JoinTable(
name ="users_roles",
joinColumns =@JoinColumn(name ="user_id"),
inverseJoinColumns =@JoinColumn(name ="role_id"))privateSet<Role> roles =newHashSet<>();}
同时,我们还需要定义一个 Role 实体,来表示用户的权限或角色:
packagecom.coderjia.boot313security.bean;importjakarta.persistence.Column;importjakarta.persistence.Entity;importjakarta.persistence.GeneratedValue;importjakarta.persistence.GenerationType;importjakarta.persistence.Id;importjakarta.persistence.Table;importlombok.Data;/**
* @author CoderJia
* @create 2024/10/19 下午 04:13
* @Description
**/@Data@Entity@Table(name ="roles")publicclassRole{@Id@GeneratedValue(strategy =GenerationType.IDENTITY)privateLong id;@Column(unique =true)privateString name;}
这样,我们就定义好了与数据库交互的基本模型,即用户和角色的关系。
3. 创建用户仓库
为了与数据库交互,我们使用 Spring Data JPA 创建一个 UserRepository,它可以查询用户并获取其角色:
packagecom.coderjia.boot313security.dao;importorg.springframework.data.jpa.repository.JpaRepository;importcom.coderjia.boot313security.bean.User;importjava.util.Optional;/**
* @author CoderJia
* @create 2024/10/19 下午 04:16
* @Description
**/publicinterfaceUserRepositoryextendsJpaRepository<User,Long>{Optional<User>findByUsername(String username);}
这个接口继承了
JpaRepository
,并提供了根据用户名查找用户的方法。我们已经完成了 Spring Boot 3 集成 Spring Data JPA 的基本配置和功能实现。运行应用后,Spring Data JPA 会自动创建数据库表,并处理数据库的 CRUD 操作。
4. Spring Security 配置
要使用 Spring Security 进行用户认证,我们需要配置
SecurityConfig
,并实现自定义的 UserDetailsService 来与数据库中的用户信息进行集成。
4.1 自定义 UserDetailsService
想从数据库加载用户信息,就需要创建一个自定义的
UserDetailsService
实现类,它的主要作用:
- 用户认证: - UserDetailsService 负责从数据源(如数据库、LDAP等)中加载用户特定的安全信息,包括用户名、密码和权限(角色)。- Spring Security 使用 UserDetailsService 来验证用户提供的凭据是否正确。
- 用户授权: - 加载用户的权限信息,以便在认证成功后进行授权检查。- 权限信息通常包括用户的角色(如 ROLE_ADMIN, ROLE_USER 等),这些角色用于控制用户可以访问的资源和操作。
packagecom.coderjia.boot313security.config;importcom.coderjia.boot313security.dao.UserRepository;importcom.coderjia.boot313security.bean.User;importcom.coderjia.boot313security.bean.Role;importorg.springframework.security.core.userdetails.UserDetails;importorg.springframework.security.core.userdetails.UserDetailsService;importorg.springframework.security.core.userdetails.UsernameNotFoundException;importorg.springframework.security.core.userdetails.User.UserBuilder;importorg.springframework.stereotype.Service;importstaticorg.springframework.security.core.userdetails.User.withUsername;/**
* @author CoderJia
* @create 2024/10/19 下午 04:20
* @Description
**/@ServicepublicclassCustomUserDetailsServiceimplementsUserDetailsService{privatefinalUserRepository userRepository;publicCustomUserDetailsService(UserRepository userRepository){this.userRepository = userRepository;}@OverridepublicUserDetailsloadUserByUsername(String username)throwsUsernameNotFoundException{User user = userRepository.findByUsername(username).orElseThrow(()->newUsernameNotFoundException("User not found"));UserBuilder builder =withUsername(user.getUsername());
builder.password(user.getPassword());
builder.roles(user.getRoles().stream().map(Role::getName).toArray(String[]::new));return builder.build();}}
这里,我们根据数据库中的用户信息加载用户,并将角色转换为 Spring Security 能识别的格式。
4.2 Spring Security 配置
现在,我们需要配置
HttpSecurity
,具体见《重学SpringBoot3-集成Spring Security(一)》,使其使用自定义的
UserDetailsService
来进行用户验证:
packagecom.coderjia.boot313security.config;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.security.config.Customizer;importorg.springframework.security.config.annotation.web.builders.HttpSecurity;importorg.springframework.security.config.annotation.web.configuration.EnableWebSecurity;importorg.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;importorg.springframework.security.crypto.password.PasswordEncoder;importorg.springframework.security.web.SecurityFilterChain;/**
* @author CoderJia
* @create 2024/10/13 下午 01:57
* @Description
**/@Configuration@EnableWebSecuritypublicclassSecurityConfig{// 通过构造函数注入自定义UserDetailsServiceprivatefinalCustomUserDetailsService userDetailsService;publicSecurityConfig(CustomUserDetailsService userDetailsService){this.userDetailsService = userDetailsService;}@BeanpublicSecurityFilterChainsecurityFilterChain(HttpSecurity http)throwsException{
http
.authorizeHttpRequests(authz -> authz
.requestMatchers("/admin/**").hasRole("ADMIN").anyRequest().authenticated()).userDetailsService(userDetailsService).formLogin(Customizer.withDefaults());return http.build();}@BeanpublicPasswordEncoderpasswordEncoder(){returnnewBCryptPasswordEncoder();}}
这段配置确保了
/admin/**
路径只能由具有
ADMIN
角色的用户访问,其他路径则需要用户登录后才能访问。
5. 使用 Bcrypt 加密密码
在实际开发中,我们不能将密码以明文形式存储在数据库中。我们可以使用 Spring Security 提供的 BCryptPasswordEncoder 来加密用户密码:
@BeanpublicPasswordEncoderpasswordEncoder(){returnnewBCryptPasswordEncoder();}
在用户注册或更新密码时,使用这个加密器对密码进行加密后再存储:
String encodedPassword = passwordEncoder.encode(plainPassword);
user.setPassword(encodedPassword);
userRepository.save(user);
6. 启动应用与测试
至此,我们已经完成了 Spring Boot 3 项目中 Spring Security 与 Spring Data JPA 的集成。
6.1 启动应用
可以启动应用,表结构已自动创建:
6.2 插入数据
创建一个用户
CoderJia
,密码使用 Bcrypt 加密:
6.3 登陆测试
访问
/admin
页面,提示登录,输入用户名和密码之后,成功登录:
7. 总结
在这篇博客中,我们通过使用 Spring Boot 3,将 Spring Security 与 Spring Data JPA 整合在一起,实现了数据库驱动的用户认证和基于角色的授权机制。通过定义用户和角色实体、实现自定义的
UserDetailsService
,我们轻松实现了用户的身份验证与访问控制。
这种结合方式不仅在安全性上提供了极大的灵活性,也让数据管理变得更加简洁高效。
在后续的博客中,我们可以进一步探讨如何使用 JWT、OAuth2 等机制来强化认证与授权的实现。
版权归原作者 CoderJia_ 所有, 如有侵权,请联系我们删除。