Spring Security基本配置指南

1. PasswordEncoder(密码加密器)

PasswordEncoder 用于对用户密码进行加密和验证。在 Spring Security 中,推荐使用BCryptPasswordEncoder。

复制代码
// 定义一个密码编码器接口,用于对密码进行加密和匹配验证
public interface PasswordEncoder {

    // 对原始密码(CharSequence 类型)进行编码(加密),返回加密后的字符串
    String encode(CharSequence var1);

    // 判断用户输入的原始密码(var1)与存储的加密密码(var2)是否匹配
    boolean matches(CharSequence var1, String var2);

    // 默认方法,用于判断当前存储的加密密码是否需要升级(比如更换了更安全的加密算法)
    // 默认返回 false,表示不需要升级
    default boolean upgradeEncoding(String encodedPassword) {
        return false;
    }
}

常见的加密方法介绍:

BCryptPasswordEncoder

算法:BCrypt 是一个基于加盐的密码哈希算法,它设计上能够防止暴力破解攻击。

特点:

  1. 加盐:每次加密都会生成一个不同的盐值,防止相同密码的密文相同。

  2. 计算成本:支持调整加密的计算复杂度(通过"工作因子"参数),更高的工作因子意味着更强的安全性。

  3. 用途:适合用来保护用户密码,防止常见的破解攻击(如字典攻击和暴力攻击)。

    @Bean
    public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
    }

NoOpPasswordEncoder

算法:该加密器直接返回明文密码,而不进行任何加密。不推荐用于生产环境,仅适用于测试或其他无需加密的场景。

特点:

  1. 不进行任何密码加密操作。

  2. 不安全,任何人都可以看到密码的明文。

  3. 用途:仅用于演示或测试。

    @Bean
    public PasswordEncoder passwordEncoder() {
    return NoOpPasswordEncoder.getInstance();
    }

Pbkdf2PasswordEncoder

算法:PBKDF2(Password-Based Key Derivation Function 2)是一种基于密码的密钥推导函数,广泛用于加密存储密码。

特点:

  1. 加盐:每次加密都会生成不同的盐值。

  2. 支持迭代次数:PBKDF2 允许你配置迭代次数,迭代次数越多,密码验证所需的计算量越大,安全性越高。

  3. 适用性:相较于 BCrypt,它在计算上更灵活,支持更多配置项。

    @Bean
    public PasswordEncoder passwordEncoder() {
    return new Pbkdf2PasswordEncoder();
    }

SCryptPasswordEncoder

算法:Scrypt 是一种记忆硬度密码哈希函数,它相较于其他算法需要更多的内存,旨在抵抗大规模并行化攻击(例如通过 GPU 进行的暴力破解)。

特点:

  1. 相较于 PBKDF2 和 BCrypt,Scrypt 需要更多的内存来计算密文,从而有效地抵抗硬件加速的破解。

  2. 可以调节内存和迭代次数,增加破解难度。

  3. 用途:适用于对高安全性有要求的场景,尤其是在抵抗 GPU 破解攻击方面更具优势。

    @Bean
    public PasswordEncoder passwordEncoder() {
    return new SCryptPasswordEncoder();
    }

Argon2PasswordEncoder

算法:Argon2 是最新的一种密码哈希算法,获得了密码学界的广泛认可,特别是它在内存和时间复杂度方面的控制,使其特别适用于密码保护。

特点:

  1. 采用 盐值 和 工作因子。

  2. 可以通过内存和时间成本来调节加密难度。

  3. 相比于其他密码哈希算法,Argon2 更具安全性。

  4. 用途:适合需要高安全性的场景,尤其是在抵抗暴力破解和并行计算方面。

    @Bean
    public PasswordEncoder passwordEncoder() {
    return new Argon2PasswordEncoder();
    }

总结:

  1. BCrypt 是目前最常用的密码加密方式,适合大多数应用。

  2. NoOpPasswordEncoder 仅适用于测试,生产环境中不推荐使用。

  3. Pbkdf2PasswordEncoder 提供更多配置选项,适合需要灵活控制加密过程的场景。

  4. SCryptPasswordEncoder 和 Argon2PasswordEncoder 提供更强的防御机制,尤其适用于高安全性要求的场景。

    public class PasswordEncoderTest {

    复制代码
     private final PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
     @Test
     public void testPasswordEncoder() {
         String password = "123456";
         String encodedPassword = passwordEncoder.encode(password);
         System.out.println("加密后密文:"+encodedPassword);
         // 验证密码是否匹配
         boolean matches = passwordEncoder.matches(password, encodedPassword);
         System.out.println("密码匹配结果:"+matches);
     }

    }

2、UserDetailsService(用户信息服务)

UserDetailsService 是一个接口,用于从数据库加载用户信息(用户名、密码、角色等)。我们需要实现它,并在自定义逻辑中查询用户。

UserDetailsService 的作用:

  1. 用户认证:提供用户认证所需的用户信息

  2. 数据源抽象:将用户数据的获取方式与认证逻辑解耦

  3. 灵活性:可以自定义从任何数据源(数据库、LDAP、内存等)加载用户

    public interface UserDetailsService {
    UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
    }

通常我们需要实现自己的 UserDetailsService,从数据库中查询用户信息。

UserDetails 是 Spring Security 中表示用户信息的接口,通常我们会创建一个类实现此接口或使用框架提供的实现类(如 org.springframework.security.core.userdetails.User)。

3. DaoAuthenticationProvider(认证提供者)

DaoAuthenticationProvider 是 Spring Security 的默认认证提供者。它依赖于 UserDetailsService 和 PasswordEncoder。DaoAuthenticationProvider 是 Spring Security 中最核心的认证提供者(AuthenticationProvider)实现之一,专门用于基于用户名/密码的表单认证。

复制代码
    /**
     * 配置密码编码器 Bean,使用 BCrypt 强散列加密算法对用户密码进行加密存储和验证
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 配置 DaoAuthenticationProvider Bean,用于基于数据库的用户认证
     * 设置用户信息服务(userDetailsService)和密码编码器(passwordEncoder)
     * @return
     */
    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(userDetailsService); // 设置自定义用户详情服务
        authProvider.setPasswordEncoder(passwordEncoder());    // 设置密码编码器,用于密码加密与验证
        return authProvider;
    }

4. SecurityFilterChain(过滤器链配置)

Spring Security 的过滤器链通过 SecurityFilterChain 进行配置。以下是常见配置项的解析:

1、CSRF(跨站请求伪造防护)

在开发阶段,可以禁用 CSRF 防护:

复制代码
.csrf(csrf -> csrf.disable())

在生产环境,建议开启 CSRF 防护,并为特定接口添加白名单(Spring Security 5.x 中,在6.0中部分方法发生变化):

复制代码
.csrf(csrf -> csrf.ignoringAntMatchers("/api/**"))


// 默认启用CSRF保护
csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());

// 禁用CSRF(前后端分离常见做法)
csrf().disable();

2、授权规则

通过 authorizeHttpRequests 配置路由访问规则:

复制代码
http.authorizeHttpRequests(auth -> auth.requestMatchers("/public/**").permitAll()
                           .requestMatchers("/admin/**").hasRole("ADMIN")
                           .anyRequest().authenticated())

permitAll()、hasRole()、authenticated()对比:

|---------------------|------------|------------|--------------|
| 方法 | 是否需要登录 | 是否检查角色 | 典型使用场景 |
| permitAll() | ❌ 不需要 | ❌ 不检查 | 首页、登录页、公开API |
| authenticated() | ✔️ 需要 | ❌ 不检查 | 普通用户后台、个人中心 |
| hasRole("XXX") | ✔️ 需要 | ✔️ 检查指定角色 | 管理员后台、权限敏感操作 |

3、自定义登录页面

通过 formLogin 配置自定义登录行为:

复制代码
.formLogin(form -> form
        .loginPage("/login")                // 登录页面路径
        .loginProcessingUrl("/perform_login") // 登录表单提交路径
        .defaultSuccessUrl("/home", true)    // 登录成功后跳转页面
        .failureUrl("/login?error")         // 登录失败后跳转页面
        .permitAll()
)


// 如果是前后端分离的项目,完全禁用表单登录功能
.formLogin().disable()

4、注销配置

通过 logout 配置用户退出登录后的行为:

复制代码
.logout(logout -> logout
        .logoutUrl("/logout")                  // 退出登录 URL
        .logoutSuccessUrl("/login?logout")     // 退出成功后跳转页面
        .permitAll()
)


.logout().disable()    // 禁用默认的/logout端点

5、HTTP Basic 认证配置

HTTP Basic 认证是 HTTP 协议定义的一种简单的认证机制,它通过 Authorization 请求头传递凭证,使用 Base64 编码(非加密)用户名和密码,是 RFC 7617 定义的标准认证方式

基本工作原理:

  1. 客户端访问受保护资源

  2. 服务器返回 401 Unauthorized 和 WWW-Authenticate: Basic 头

  3. 浏览器弹出登录对话框

  4. 用户输入凭据后,浏览器发送 Authorization: Basic base64(username:password) 头

  5. 服务器验证凭据并返回资源或再次 401

    .httpBasic(); // 启用HTTP Basic认证

    .httpBasic().disable(); // 禁用HTTP Basic

6、会话管理

会话管理是Web安全的重要组成部分,它控制着用户登录后的会话行为。Spring Security提供了强大的会话管理功能,包括会话并发控制、会话过期处理等。

限制每个用户只能有一个会话,并配置会话过期后的行为:

复制代码
.sessionManagement(session -> session
                   .maximumSessions(1)                // 每个用户限制一个会话
                   .expiredUrl("/login?expired")     // 会话过期后跳转页面
                  )

//声明不依赖 Session 维护认证状态。
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 无状态

7、Remember-Me 功能

Remember-Me 是 Spring Security 提供的一种持久化登录机制,允许用户在关闭浏览器后再次访问网站时无需重新登录,通常通过 Cookie 实现。

复制代码
.rememberMe()
.key("uniqueAndSecretKey") // 加密密钥
.tokenValiditySeconds(86400 * 30) // 30天有效期
.rememberMeParameter("remember-me") // 表单参数名
.rememberMeCookieName("remember-me") // Cookie名
.tokenRepository(persistentTokenRepository()); // 持久化存储


// 禁用传统的基于Cookie的Remember-Me
.rememberMe(remember -> remember.disable());

8、headers安全头配置

Spring Security 的 headers() 配置用于添加各种安全相关的 HTTP 响应头,这些头部可以帮助浏览器防范常见攻击。

复制代码
.headers(headers -> headers
         // 禁用Spring Security提供的所有默认安全头
         .defaultsDisabled()
         // 启用缓存控制头,防止敏感信息被缓存
         .cacheControl(withDefaults())
         // 启用内容类型选项头,防止MIME嗅探攻击
         .contentTypeOptions(withDefaults())
         // 启用HTTP严格传输安全头(HSTS),强制使用HTTPS
         .httpStrictTransportSecurity(withDefaults())
         // 启用X-Frame-Options头,防止点击劫持攻击
         .frameOptions(withDefaults())
         // 启用X-XSS-Protection头,启用浏览器内置的XSS防护
         .xssProtection(withDefaults())
         // 启用Referrer-Policy头,控制Referer信息的发送策略
         .referrerPolicy(withDefaults())
        )

9、SpringSecurity 异常处理配置

Spring Security 的 exceptionHandling() 用于自定义认证和授权过程中的异常处理行为。

复制代码
http
.exceptionHandling() // 开启异常处理配置
.authenticationEntryPoint(authenticationEntryPoint()) // 认证入口点
.accessDeniedHandler(accessDeniedHandler()) // 访问拒绝处理器

10、跨域资源共享(CORS)配置

Spring Security 默认禁用 CORS,需要显式配置才能启用跨域支持。

复制代码
.cors().configurationSource(corsConfigurationSource())

.cors().disable() // 同源不需要CORS
cors与csrf使用策略

1. 传统Web应用(同源)

复制代码
http
.cors().disable() // 同源不需要CORS
.csrf().csrfTokenRepository(new CookieCsrfTokenRepository()) // 启用CSRF

2. 前后端分离项目(跨域)

复制代码
http
.cors().configurationSource(corsConfigurationSource()).and() // 配置CORS
.csrf().disable() // 通常禁用CSRF,改用JWT等Token方案

/**
* 定义一个Bean,用于配置跨域资源共享(CORS)策略
* @return
*/
@Bean
public CorsConfigurationSource corsConfigurationSource() {
    // 创建CORS配置对象
    CorsConfiguration config = new CorsConfiguration();
    // 设置允许的来源,只允许来自 https://trusted.com 的请求
    config.setAllowedOrigins(Arrays.asList("https://trusted.com"));
    // 设置允许的HTTP方法,仅允许 GET 和 POST 请求
    config.setAllowedMethods(Arrays.asList("GET", "POST"));
    // 允许发送凭据(如Cookies、Authorization头等)
    config.setAllowCredentials(true);

    // 创建基于URL的CORS配置源,用于将CORS配置应用到具体的URL路径上
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    // 将上述CORS配置应用到所有路径(/** 表示所有接口)
    source.registerCorsConfiguration("/**", config);
    // 返回CORS配置源,供Spring Security或Web框架使用
    return source;
}

配置 HTTP 安全过滤器链

复制代码
/**
     * 配置 HTTP 安全过滤器链
     * * 该过滤器链的优先级为1,表示它将优先于其他过滤器链执行
     * @param http
     * @return
     * @throws Exception
     */
@Bean
@Order(1)
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
    http
    // 1. 授权配置:设置所有请求(anyRequest)都需要用户认证(authenticated)
    .authorizeHttpRequests(auth -> auth
                           .anyRequest().authenticated()
                          )
    // 2. 表单登录:启用Spring Security默认的表单登录功能(包括登录页和登录处理逻辑)
    .formLogin(withDefaults())
    // 3. HTTP Basic认证:启用HTTP Basic方式的认证(浏览器弹窗方式)
    .httpBasic(withDefaults())
    // 4. 记住我功能:启用"记住我"功能,默认有效期通常为14天
    .rememberMe(withDefaults())
    // 5. 登出功能:启用默认的登出逻辑,如清除会话、cookie等
    .logout(withDefaults())
    // 6. CSRF保护:启用跨站请求伪造(CSRF)防护,默认是开启的
    .csrf(withDefaults())
    // 7. 会话管理:配置会话相关策略
    .sessionManagement(session -> session
                       // 如果需要则创建会话(默认策略),即不主动创建,按需使用
                       .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
                       // 同一用户最多只能有一个活跃会话
                       .maximumSessions(1)
                       // 当达到最大会话数时,不允许新登录(false表示允许新登录踢掉旧会话)
                       .maxSessionsPreventsLogin(false)
                      )
    // 8. 安全头配置:自定义HTTP安全响应头
    .headers(headers -> headers
             // 禁用Spring Security提供的所有默认安全头
             .defaultsDisabled()
             // 启用缓存控制头,防止敏感信息被缓存
             .cacheControl(withDefaults())
             // 启用内容类型选项头,防止MIME嗅探攻击
             .contentTypeOptions(withDefaults())
             // 启用HTTP严格传输安全头(HSTS),强制使用HTTPS
             .httpStrictTransportSecurity(withDefaults())
             // 启用X-Frame-Options头,防止点击劫持攻击
             .frameOptions(withDefaults())
             // 启用X-XSS-Protection头,启用浏览器内置的XSS防护
             .xssProtection(withDefaults())
             // 启用Referrer-Policy头,控制Referer信息的发送策略
             .referrerPolicy(withDefaults())
            )
    // 9. 异常处理:使用Spring Security默认的异常处理逻辑,如403、401等
    .exceptionHandling(withDefaults())
    // 10. CORS配置:配置跨域资源共享(CORS),默认是禁用的
    .cors(withDefaults());
    // 构建并返回配置好的安全过滤器链
    return http.build();
}