Spring Security 6.x实战:从零构建用户管理系统,彻底掌握认证授权核心机制
每次看到Spring Security的配置就头疼?明明跟着教程一步步操作,却总在某个环节卡住?这可能是大多数初中级开发者学习Spring Security时的真实写照。本文将带你用Spring Boot 3.x + Spring Security 6.x构建一个完整的用户管理系统,在实战中理解那些"只可意会"的核心流程。
1. 项目初始化与环境搭建
我们先从最基础的Spring Boot项目开始。使用Spring Initializr创建项目时,除了选择Spring Web和Spring Security依赖外,建议加上Lombok和Thymeleaf简化开发:
bash复制curl https://start.spring.io/starter.zip \
-d dependencies=web,security,lombok,thymeleaf \
-d javaVersion=17 \
-d packaging=jar \
-d type=gradle-project \
-o user-management.zip
解压后,你会看到一个标准的Spring Boot项目结构。Spring Security 6.x默认启用了CSRF保护,并采用了更严格的默认安全配置。我们先创建一个简单的控制器测试基础功能:
java复制@Controller
public class HomeController {
@GetMapping("/")
public String home() {
return "index";
}
@GetMapping("/admin")
public String admin() {
return "admin";
}
}
启动项目后访问首页,你会被自动重定向到/login页面——这就是Spring Security的默认行为。但此时我们还没有任何用户配置,接下来让我们解决这个问题。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 用户认证:从内存存储到数据库集成
2.1 基础内存认证配置
Spring Security 6.x推荐使用Lambda DSL进行配置,代码更加简洁:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/", "/home").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.permitAll()
)
.logout(logout -> logout
.permitAll()
);
return http.build();
}
@Bean
public UserDetailsService userDetailsService() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
UserDetails admin = User.withDefaultPasswordEncoder()
.username("admin")
.password("admin")
.roles("USER", "ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
}
注意:生产环境绝对不要使用
withDefaultPasswordEncoder(),这里仅用于演示。我们稍后会介绍正确的密码加密方式。
2.2 数据库用户存储实战
实际项目中,用户信息通常存储在数据库中。我们先定义用户实体和Repository:
java复制@Entity
@Data
@NoArgsConstructor
public class User {
@Id @GeneratedValue(strategy = IDENTITY)
private Long id;
private String username;
private String password;
private String roles; // 格式:"ROLE_USER,ROLE_ADMIN"
}
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsername(String username);
}
然后实现自定义的UserDetailsService:
java复制@Service
@RequiredArgsConstructor
public class CustomUserDetailsService implements UserDetailsService {
private final UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
return org.springframework.security.core.userdetails.User.bu
