第19章 SpringBoot 安全

掌握SpringBoot Security安全框架和最佳实践

💻 查看完整代码 - 在线IDE体验

🎯 学习目标

  • 安全基础:了解Web应用安全原理
  • Spring Security:掌握安全框架配置
  • 认证授权:实现用户认证和权限控制
  • JWT集成:无状态Token认证
  • OAuth2:第三方登录集成
  • 安全防护:防范常见安全攻击

🔧 核心概念

  • Authentication:身份认证
  • Authorization:权限授权
  • Principal:用户主体
  • Authorities:用户权限
  • SecurityContext:安全上下文
  • Filter Chain:安全过滤器链

📦 依赖配置

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- Web支持 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- JWT支持 --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.5</version> </dependency> <!-- 数据库支持 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>

🔄 安全架构流程

请求到达
安全过滤器
身份认证
权限检查
访问控制
业务处理

🛡️ 安全层次架构

多层安全防护体系

🔐 认证层 - Authentication Layer
🔑 授权层 - Authorization Layer
🔒 加密层 - Encryption Layer
✅ 验证层 - Validation Layer

⚙️ 基础安全配置

@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig { @Autowired private UserDetailsService userDetailsService; @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(authz -> authz .requestMatchers("/api/public/**").permitAll() .requestMatchers("/api/admin/**").hasRole("ADMIN") .requestMatchers("/api/user/**").hasAnyRole("USER", "ADMIN") .anyRequest().authenticated() ) .formLogin(form -> form .loginPage("/login") .defaultSuccessUrl("/dashboard") .permitAll() ) .logout(logout -> logout .logoutUrl("/logout") .logoutSuccessUrl("/login?logout") .permitAll() ) .sessionManagement(session -> session .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) .maximumSessions(1) .maxSessionsPreventsLogin(false) ) .csrf(csrf -> csrf.disable()) .headers(headers -> headers.frameOptions().deny()); return http.build(); } }

👤 用户认证服务

@Service public class CustomUserDetailsService implements UserDetailsService { @Autowired private UserRepository userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUsername(username) .orElseThrow(() -> new UsernameNotFoundException( "用户不存在: " + username)); return org.springframework.security.core.userdetails.User.builder() .username(user.getUsername()) .password(user.getPassword()) .authorities(getAuthorities(user.getRoles())) .accountExpired(false) .accountLocked(false) .credentialsExpired(false) .disabled(false) .build(); } private Collection<? extends GrantedAuthority> getAuthorities(Set<Role> roles) { return roles.stream() .map(role -> new SimpleGrantedAuthority("ROLE_" + role.getName())) .collect(Collectors.toList()); } }

🔑 JWT Token配置

@Component public class JwtTokenProvider { private String jwtSecret = "mySecretKey"; private int jwtExpirationInMs = 604800000; // 7天 public String generateToken(Authentication authentication) { UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal(); Date expiryDate = new Date(System.currentTimeMillis() + jwtExpirationInMs); return Jwts.builder() .setSubject(Long.toString(userPrincipal.getId())) .setIssuedAt(new Date()) .setExpiration(expiryDate) .signWith(SignatureAlgorithm.HS512, jwtSecret) .compact(); } public Long getUserIdFromJWT(String token) { Claims claims = Jwts.parser() .setSigningKey(jwtSecret) .parseClaimsJws(token) .getBody(); return Long.parseLong(claims.getSubject()); } public boolean validateToken(String authToken) { try { Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken); return true; } catch (JwtException | IllegalArgumentException e) { return false; } } }

🔐 认证方式对比

Session-Cookie 认证
JWT Token 认证
OAuth2 第三方认证
Basic 基础认证
Digest 摘要认证

🛡️ 安全功能特性

CSRF 防护
跨站请求伪造攻击防护
XSS 防护
跨站脚本攻击防护
SQL 注入防护
数据库注入攻击防护
会话管理
用户会话安全管理
密码加密
用户密码安全存储
权限控制
细粒度访问控制

🔒 方法级安全

@RestController @RequestMapping("/api/admin") public class AdminController { @PreAuthorize("hasRole('ADMIN')") @GetMapping("/users") public List<User> getAllUsers() { return userService.findAll(); } @PreAuthorize("hasRole('ADMIN') and #id == authentication.principal.id") @DeleteMapping("/users/{id}") public void deleteUser(@PathVariable Long id) { userService.deleteById(id); } @PostAuthorize("returnObject.username == authentication.name") @GetMapping("/profile") public User getProfile() { return userService.getCurrentUser(); } @Secured({"ROLE_ADMIN", "ROLE_MANAGER"}) @GetMapping("/reports") public List<Report> getReports() { return reportService.findAll(); } }

🌐 OAuth2 集成

# application.yml spring: security: oauth2: client: registration: google: client-id: your-google-client-id client-secret: your-google-client-secret scope: profile, email github: client-id: your-github-client-id client-secret: your-github-client-secret scope: user:email provider: google: authorization-uri: https://accounts.google.com/o/oauth2/auth token-uri: https://oauth2.googleapis.com/token user-info-uri: https://www.googleapis.com/oauth2/v2/userinfo user-name-attribute: email @Configuration public class OAuth2Config { @Bean public OAuth2UserService<OAuth2UserRequest, OAuth2User> oauth2UserService() { return new CustomOAuth2UserService(); } }

📊 安全配置对比

认证方式 优点 缺点 适用场景
Session-Cookie 简单易用,服务端控制 不适合分布式 传统Web应用
JWT Token 无状态,跨域支持 Token泄露风险 微服务架构
OAuth2 第三方授权,安全 配置复杂 开放平台
Basic Auth 简单直接 安全性较低 内部API
API Key 轻量级 功能有限 公开API

🎯 安全最佳实践

安全开发建议

1. 密码策略:强制复杂密码,定期更换

2. 输入验证:严格验证所有用户输入

3. 权限最小化:遵循最小权限原则

4. 安全传输:使用HTTPS加密传输

5. 日志审计:记录安全相关操作

6. 定期更新:及时更新安全补丁

7. 安全测试:定期进行安全测试

8. 错误处理:避免泄露敏感信息

🎉 恭喜完成第19章学习!

你已经掌握了SpringBoot Security安全的核心技能,接下来学习事务管理!

🚀 下一章:SpringBoot Transaction 🏠 返回课程首页