🎯 学习目标
- 安全基础:了解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 摘要认证
🔒 方法级安全
@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. 错误处理:避免泄露敏感信息