spring security 超详细使用教程(接入springboot、前后端分离)

Spring Security 超详细使用教程:接入 Spring Boot 与前后端分离

引言:Spring Security,Spring Boot 安全的“守护神”

Spring Security 是 Spring 生态中处理认证(Authentication)和授权(Authorization)的强大框架,它无缝集成 Spring Boot,提供从基本认证到 OAuth2 的全面解决方案。在前后端分离架构中(如 React/Vue 前端 + Spring Boot 后端),Spring Security 常结合 JWT(JSON Web Token)实现无状态认证,避免传统 Session 的跨域问题。根据官方指南,Spring Security 能轻松保护 REST API,确保只有授权用户访问资源。 2026 年,随着 Spring Boot 3.x 的普及,这一框架支持虚拟线程和 GraalVM Native 编译,提升了性能和安全性。本教程从基础接入入手,逐步深入前后端分离实战,覆盖依赖、配置、JWT 集成和常见坑。目标:读完后,你能独立构建一个安全的 API 系统,提升应用安全性 50%+。预计阅读时长:30 分钟。准备 IntelliJ IDEA 和 Maven?立即新建 Spring Boot 项目测试基本认证!

核心概念:Spring Security 基础速览

Spring Security 的核心是过滤器链(Filter Chain),它拦截请求,处理认证/授权。以下表格对比关键概念(基于 Spring Security 6.x,兼容 Boot 3.x):

概念定义与作用关键组件/注解前后端分离适用性常见误区
认证(Authentication)验证用户身份(如用户名/密码、JWT)UserDetailsService, AuthenticationManager高:用 JWT 令牌替换 Session忽略密码加密(BCrypt)
授权(Authorization)检查权限(如角色/方法级)@PreAuthorize, SecurityFilterChain高:基于 JWT 声明(claims)过度配置导致性能瓶颈
过滤器链拦截请求的过滤器序列HttpSecurity 配置中:自定义 JWT 过滤器默认启用 CSRF 冲突 CORS
JWT 集成无状态令牌,用于前后端分离JwtAuthenticationToken高:API 首选密钥泄露/过期未处理
OAuth2第三方登录(如 Google)@EnableOAuth2Client高:社交登录配置 issuer-uri 错误

解读:前后端分离时,禁用 Session(stateless),用 JWT 携带用户信息。默认 Spring Security 启用基本认证,需自定义配置。

依赖与项目准备

步骤1:创建 Spring Boot 项目

  • 使用 Spring Initializr(https://start.spring.io)生成项目:选择 Spring Boot 3.x、Java 21+、Maven。
  • 添加依赖:Web(spring-boot-starter-web)、Security(spring-boot-starter-security)、JWT(spring-boot-starter-oauth2-resource-server 或 jjwt)。
  • pom.xml 示例:
  <dependencies>
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-security</artifactId>
      </dependency>
      <dependency>
          <groupId>org.springframework.security</groupId>
          <artifactId>spring-security-oauth2-resource-server</artifactId>
      </dependency>
      <dependency>
          <groupId>org.springframework.security</groupId>
          <artifactId>spring-security-oauth2-jose</artifactId>
      </dependency>
      <dependency> <!-- JWT 解析 -->
          <groupId>io.jsonwebtoken</groupId>
          <artifactId>jjwt-api</artifactId>
          <version>0.12.3</version>
      </dependency>
      <dependency>
          <groupId>io.jsonwebtoken</groupId>
          <artifactId>jjwt-impl</artifactId>
          <version>0.12.3</version>
          <scope>runtime</scope>
      </dependency>
      <dependency>
          <groupId>io.jsonwebtoken</groupId>
          <artifactId>jjwt-jackson</artifactId>
          <version>0.12.3</version>
          <scope>runtime</scope>
      </dependency>
  </dependencies>

步骤2:基本配置

  • 添加 Security 后,Spring Boot 默认启用基本认证(用户名 user,密码控制台打印)。测试:运行应用,访问 http://localhost:8080,弹出登录框。

基础认证配置:用户名/密码验证

步骤3:自定义用户服务

  • 创建 UserDetailsService 实现类,加载用户数据(可从数据库)。
  • 代码示例(SecurityConfig.java):
  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.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
  public class SecurityConfig {

      @Bean
      public PasswordEncoder passwordEncoder() {
          return new BCryptPasswordEncoder();  // 密码加密
      }

      @Bean
      public UserDetailsService userDetailsService() {
          UserDetails user = User.withUsername("admin")
                  .password(passwordEncoder().encode("123456"))
                  .roles("ADMIN")
                  .build();
          return new InMemoryUserDetailsManager(user);  // 内存用户,生产用数据库
      }

      @Bean
      public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
          http
                  .authorizeHttpRequests(auth -> auth
                          .requestMatchers("/public/**").permitAll()  // 公开路径
                          .anyRequest().authenticated()  // 其他需认证
                  )
                  .formLogin(form -> form  // 表单登录
                          .loginPage("/login")  // 自定义登录页(前后端分离可忽略)
                          .permitAll()
                  )
                  .logout(logout -> logout.permitAll());
          return http.build();
      }
  }
  • 测试:访问受保护路径,输入 admin/123456 登录。

前后端分离:JWT 认证集成

前后端分离时,禁用表单登录和 CSRF,用 JWT 处理认证。

步骤4:JWT 配置

  • 创建 JWT 工具类:
  import io.jsonwebtoken.*;
  import java.util.Date;

  public class JwtUtils {
      private static final String SECRET = "your_secret_key";  // 密钥
      private static final long EXPIRATION = 86400000;  // 1天

      public static String generateToken(String username) {
          return Jwts.builder()
                  .setSubject(username)
                  .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION))
                  .signWith(Keys.hmacShaKeyFor(SECRET.getBytes()))
                  .compact();
      }

      public static String getUsernameFromToken(String token) {
          return Jwts.parserBuilder()
                  .setSigningKey(Keys.hmacShaKeyFor(SECRET.getBytes()))
                  .build()
                  .parseClaimsJws(token)
                  .getBody()
                  .getSubject();
      }

      public static boolean validateToken(String token) {
          try {
              Jwts.parserBuilder().setSigningKey(Keys.hmacShaKeyFor(SECRET.getBytes())).build().parseClaimsJws(token);
              return true;
          } catch (Exception e) {
              return false;
          }
      }
  }

步骤5:自定义 JWT 过滤器

  • 更新 SecurityConfig:
  // ... 省略前部分

  @Bean
  public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
      http
              .csrf(csrf -> csrf.disable())  // 前后端分离禁用 CSRF
              .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))  // 无状态
              .authorizeHttpRequests(auth -> auth
                      .requestMatchers("/login").permitAll()
                      .anyRequest().authenticated()
              )
              .addFilterBefore(new JwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);  // 自定义过滤器
      return http.build();
  }
  • JwtAuthenticationFilter.java:
  import jakarta.servlet.FilterChain;
  import jakarta.servlet.http.HttpServletRequest;
  import jakarta.servlet.http.HttpServletResponse;
  import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  import org.springframework.security.core.context.SecurityContextHolder;
  import org.springframework.security.core.userdetails.UserDetails;
  import org.springframework.web.filter.OncePerRequestFilter;

  public class JwtAuthenticationFilter extends OncePerRequestFilter {
      @Override
      protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws Exception {
          String token = request.getHeader("Authorization");
          if (token != null && token.startsWith("Bearer ")) {
              token = token.substring(7);
              if (JwtUtils.validateToken(token)) {
                  String username = JwtUtils.getUsernameFromToken(token);
                  // 从UserDetailsService加载用户
                  UserDetails userDetails = userDetailsService().loadUserByUsername(username);
                  UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                  SecurityContextHolder.getContext().setAuthentication(auth);
              }
          }
          filterChain.doFilter(request, response);
      }
  }

步骤6:登录接口生成 JWT

  • LoginController.java:
  import org.springframework.security.authentication.AuthenticationManager;
  import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  import org.springframework.security.core.Authentication;
  import org.springframework.web.bind.annotation.PostMapping;
  import org.springframework.web.bind.annotation.RequestBody;
  import org.springframework.web.bind.annotation.RestController;

  @RestController
  public class LoginController {
      private final AuthenticationManager authenticationManager;

      public LoginController(AuthenticationManager authenticationManager) {
          this.authenticationManager = authenticationManager;
      }

      @PostMapping("/login")
      public String login(@RequestBody LoginRequest request) {
          Authentication authentication = authenticationManager.authenticate(
                  new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword())
          );
          return JwtUtils.generateToken(request.getUsername());
      }
  }

  public class LoginRequest {
      private String username;
      private String password;
      // getters/setters
  }
  • 前端:用 Axios 发送 POST /login,获取 JWT,后续请求加 Header: Authorization: Bearer {token}。

授权与方法级安全

步骤7:角色授权

  • 在 SecurityConfig 加 @EnableMethodSecurity
  • Controller 示例:
  @RestController
  public class AdminController {
      @GetMapping("/admin")
      @PreAuthorize("hasRole('ADMIN')")  // 方法级授权
      public String admin() {
          return "Admin Access";
      }
  }

常见问题与优化

  • CORS:前后端分离加 CORS 配置:
  @Bean
  public CorsConfigurationSource corsConfigurationSource() {
      CorsConfiguration config = new CorsConfiguration();
      config.setAllowedOrigins(List.of("http://localhost:3000"));  // 前端地址
      config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
      config.setAllowedHeaders(List.of("*"));
      UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
      source.registerCorsConfiguration("/**", config);
      return source;
  }
  • 性能:大表 JWT 验证用缓存;生产用 RSA 密钥签名。
  • OAuth2:扩展到第三方登录,配置 issuer-uri 和 client-id< g rok:render type=”render_inline_citation”>
    9

结语:Spring Security,构建安全的 API 堡垒

从基本认证到 JWT 前后端分离,Spring Security 让安全配置变得优雅而强大——在春川的春日午后(当前 KST 11:30,2026.3.7),试着运行这个配置,Postman 测试 /login 获取 JWT,你将感受到安全的脉动!实践挑战:集成数据库用户存储。需 OAuth2 扩展或代码调试?分享你的项目细节,我帮优化。参考:Spring 官方指南与 Baeldung 教程。 Go secure, build robust!

文章已创建 4944

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部