Spring Security 实战

Web 应用的安全基石:认证(你是谁)和授权(你能做什么)。Spring Security 是 Java 生态最成熟的安全框架,本文讲清核心配置。

Spring Security 配图:深蓝色背景上带挂锁的盾牌立于平台之上,两侧是访问控制闸机,扁平科技插画
Spring Security:认证与授权的第一道防线

一、核心概念

认证(Authentication)验证用户身份,比如登录。授权(Authorization)验证用户权限,比如谁能访问管理后台。Spring Security 通过过滤器链(Filter Chain)处理每个请求。

概念说明
SecurityFilterChain安全过滤器链,拦截所有请求
UserDetailsService加载用户信息
PasswordEncoder密码加密验证
JwtTokenProviderJWT 生成与解析

二、依赖与基础配置

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.5</version>
</dependency>
@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.disable())
            .sessionManagement(session -> session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            )
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/auth/**").permitAll()
                .requestMatchers("/api/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            );
        return http.build();
    }
}

三、用户认证

@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String username) {
        User user = userRepository.findByUsername(username);
        return org.springframework.security.core.userdetails.User
            .withUsername(user.getUsername())
            .password(user.getPassword())
            .roles(user.getRole())
            .build();
    }
}
密码加密:永远不要明文存储密码。用 BCryptPasswordEncoder,它自带盐值,每次加密结果不同但可验证。

四、JWT 无状态登录

@Component
public class JwtTokenProvider {

    @Value("${jwt.secret}")
    private String secret;

    public String generateToken(String username) {
        return Jwts.builder()
            .setSubject(username)
            .setIssuedAt(new Date())
            .setExpiration(new Date(System.currentTimeMillis() + 86400000))
            .signWith(SignatureAlgorithm.HS256, secret)
            .compact();
    }

    public String getUsername(String token) {
        return Jwts.parser()
            .setSigningKey(secret)
            .parseClaimsJws(token)
            .getBody()
            .getSubject();
    }
}

五、方法级权限控制

@RestController
@RequestMapping("/api/admin")
public class AdminController {

    @PreAuthorize("hasRole('ADMIN')")
    @DeleteMapping("/users/{id}")
    public void deleteUser(@PathVariable Long id) {
        userService.delete(id);
    }

    @PreAuthorize("hasAnyRole('ADMIN','EDITOR')")
    @PutMapping("/posts/{id}")
    public void updatePost(@PathVariable Long id, @RequestBody Post post) {
        postService.update(id, post);
    }
}

六、常见坑

第一,CSRF:前后端分离 + JWT 无状态时可以关掉 CSRF。第二,CORS:跨域请求要在 Security 配置里放行。第三,默认密码:Spring Boot 启动时会打印随机密码,生产环境必须换掉。

七、总结

Spring Security 的核心三步:配置 SecurityFilterChain 定义访问规则、实现 UserDetailsService 加载用户、用 JWT 做无状态认证。记住:安全是纵深防御,认证和授权只是第一道防线。