java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Spring Security6.3.x使用

Spring Security6.3.x的使用指南与注意事项

作者:墨鸦_Cormorant

Spring Security 6.3.1基于现代化架构,提供简洁配置、增强默认安全性和OAuth2.1/OIDC支持,采用LambdaDSL和组件化设计,涵盖用户认证、方法级权限控制及资源服务器配置,强调PasswordEncoder、HTTPS、CSRF保护等最佳实践,下面是Spring Security 6.3.1 的使用指南,一起学习吧

介绍

Spring Security 6.3.1 是一个重要的版本更新,它建立在 Spring Security 6 的核心现代化架构之上,提供了更简洁的配置、更好的默认安全性以及对最新安全标准的支持。以下是一个 Spring Security 6.3.1 的使用指南,涵盖核心概念、配置和常见任务:

核心理念:

基础配置 (Servlet 应用 - 使用 Lambda DSL)

添加依赖 (Maven):

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
    <version>3.2.0</version> <!-- Spring Boot 3.2.x 通常包含 Spring Security 6.3.x -->
</dependency>

核心配置类 (SecurityConfig)

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.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity // 启用 Spring Security Web 支持
public class SecurityConfig {
    // 核心配置:定义安全过滤器链 (SecurityFilterChain)
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            // 授权配置 (核心)
            .authorizeHttpRequests(authorize -> authorize
                .requestMatchers("/", "/home", "/public/**", "/css/**", "/js/**", "/images/**").permitAll() // 允许所有人访问
                .requestMatchers("/user/**").hasRole("USER") // 需要 USER 角色
                .requestMatchers("/admin/**").hasRole("ADMIN") // 需要 ADMIN 角色
                .anyRequest().authenticated() // 其他所有请求都需要认证
            )
            // 表单登录配置
            .formLogin(formLogin -> formLogin
                //.loginPage("/login") // 自定义登录页路径。不指定则使用默认登录页
                .permitAll() // 允许所有人访问登录页
                .defaultSuccessUrl("/dashboard") // 登录成功后的默认跳转页
            )
            // 退出登录配置
            .logout(logout -> logout
                .logoutUrl("/logout") // 退出登录的 URL (默认也是 /logout)
                .logoutSuccessUrl("/login?logout") // 退出成功后的跳转页
                .permitAll()
            )
            // 异常处理 (如访问拒绝)
            .exceptionHandling(exceptionHandling -> exceptionHandling
                .accessDeniedPage("/access-denied") // 自定义访问拒绝页
            )
            // 启用 HTTP Basic 认证 (可选,常用于 API)
            //.httpBasic(Customizer.withDefaults())
            // 启用 CSRF 保护 (默认启用,对于 API 可能需要禁用)
            //.csrf(csrf -> csrf.disable()); // 谨慎禁用!
        return http.build();
    }
    // 配置内存用户存储 (仅用于演示/测试,生产环境用数据库)
    @Bean
    public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {
        UserDetails user = User.builder()
            .username("user")
            .password(passwordEncoder.encode("password")) // 必须加密!
            .roles("USER")
            .build();
        UserDetails admin = User.builder()
            .username("admin")
            .password(passwordEncoder.encode("adminpass"))
            .roles("USER", "ADMIN")
            .build();
        return new InMemoryUserDetailsManager(user, admin);
    }
    // 配置密码编码器 (强制要求,不能使用明文!)
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(); // 推荐 BCrypt
        // 其他选项: Pbkdf2PasswordEncoder, SCryptPasswordEncoder, Argon2PasswordEncoder, DelegatingPasswordEncoder
    }
}

关键配置详解(Lambda DSL)

.rememberMe(remember -> remember
    .key("uniqueAndSecretKey")
    .tokenValiditySeconds(86400) // 1天
)

用户认证 (进阶)

@Service
public class JpaUserDetailsService implements UserDetailsService {
    private final UserRepository userRepository;
    public JpaUserDetailsService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return userRepository.findByUsername(username)
                .map(SecurityUser::new) // 将你的领域用户转换为 UserDetails
                .orElseThrow(() -> new UsernameNotFoundException("User not found: " + username));
    }
}
@Bean
public PasswordEncoder passwordEncoder() {
    return PasswordEncoderFactories.createDelegatingPasswordEncoder(); // 推荐:支持多种编码,默认 BCrypt
    // 或 return new BCryptPasswordEncoder();
}

方法级安全(Method Security)

@Configuration
@EnableMethodSecurity
public class MethodSecurityConfig {
    // ...
}
@Service
public class UserService {
    @PreAuthorize("hasRole('ADMIN') or #id == authentication.principal.id") // SpEL 示例:允许管理员或用户自己访问
    public User getUserById(Long id) {
        // ...
    }
    @PreAuthorize("hasAuthority('USER_DELETE')")
    public void deleteUser(Long id) {
        // ...
    }
}

OAuth2 / OIDC 资源服务器(保护 API)

Spring Security 6 对 OAuth2 资源服务器的配置进行了显著简化。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://your-auth-server.com/realms/your-realm
# 或者
# spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://your-auth-server.com/jwks
@Bean
SecurityFilterChain resourceServerSecurityFilterChain(HttpSecurity http) throws Exception {
    http
        .securityMatcher("/api/**") // 只对 /api/** 路径应用此安全配置
        .authorizeHttpRequests(authorize -> authorize
            .anyRequest().authenticated() // API 端点都需要认证
        )
        .oauth2ResourceServer(oauth2 -> oauth2
            .jwt(Customizer.withDefaults()) // 使用 JWT 作为承载令牌格式
            // .opaqueToken(Customizer.withDefaults()) // 使用不透明令牌
        );
    return http.build();
}

Spring Security 会自动使用配置的 JwtDecoder 验证 JWT 签名、过期时间等,并提取声明 (Claims) 构建 JwtAuthenticationToken

@GetMapping("/api/userinfo")
public Map<String, Object> getUserInfo(@AuthenticationPrincipal Jwt jwt) {
    return Map.of(
        "username", jwt.getSubject(),
        "email", jwt.getClaimAsString("email"),
        "scopes", jwt.getClaimAsStringList("scope")
    );
}

最佳实践与注意事项

  1. 始终使用 PasswordEncoder: 绝对不要存储明文密码。
  2. 最小权限原则: 只授予用户完成工作所必需的权限。
  3. 保持依赖更新: Spring Security 会修复漏洞,及时更新到最新稳定版。
  4. 理解 CSRF: 对于有状态 Web 应用(使用 Session 和 Cookie),保持 CSRF 保护启用。对于纯无状态 API(如只使用 JWT 的 API),可以禁用 CSRF (csrf.disable())。
  5. HTTPS: 在生产环境中始终使用 HTTPS。
  6. 安全头: Spring Security 默认设置了许多安全相关的 HTTP 响应头 (如 X-Content-Type-Options, X-Frame-Options, Strict-Transport-Security, Content-Security-Policy 等)。理解并根据需要配置它们 (http.headers(headers -> headers ...))。
  7. 日志与监控: 记录安全相关事件(登录成功/失败、访问拒绝等)并进行监控。
  8. WebSecurityConfigurerAdapter: 在 Spring Security 5.7 中已弃用,在 6.x 中移除。始终使用 SecurityFilterChain Bean 配置。
  9. 谨慎使用 permitAll(): 确保只对真正公开的资源使用它。
  10. 测试: 编写单元测试和集成测试来验证你的安全配置是否按预期工作。使用 @WithMockUser, @WithUserDetails, @WithAnonymousUser 等注解进行模拟用户测试。

参考

到此这篇关于Spring Security6.3.x使用指南的文章就介绍到这了,更多相关Spring Security6.3.x使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文