Spring Security
2026/3/26大约 3 分钟
Spring Security
Spring Security是强大且高度可定制的认证和访问控制框架。
核心概念
认证 vs 授权
- 认证(Authentication):你是谁?(登录)
- 授权(Authorization):你能做什么?(权限)
核心组件
┌─────────────────────────────────────────────────────────────┐
│ Security Filter Chain │
├─────────────────────────────────────────────────────────────┤
│ UsernamePasswordAuthenticationFilter → 认证 │
│ JWTAuthenticationFilter → Token认证 │
│ FilterSecurityInterceptor → 授权检查 │
└─────────────────────────────────────────────────────────────┘基础配置
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>安全配置
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// 禁用CSRF(前后端分离)
.csrf(csrf -> csrf.disable())
// 配置请求授权
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll()
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
// Session管理
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
// 添加JWT过滤器
.addFilterBefore(jwtAuthenticationFilter(),
UsernamePasswordAuthenticationFilter.class)
// 异常处理
.exceptionHandling(ex -> ex
.authenticationEntryPoint(jwtAuthenticationEntryPoint)
);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}JWT认证
JWT工具类
@Component
public class JwtUtils {
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private long expiration;
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return Jwts.builder()
.setClaims(claims)
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + expiration))
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
public String getUsernameFromToken(String token) {
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody()
.getSubject();
}
public boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(secret).parseClaimsJws(token);
return true;
} catch (Exception e) {
return false;
}
}
}JWT过滤器
@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtUtils jwtUtils;
private final UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String token = getTokenFromRequest(request);
if (token != null && jwtUtils.validateToken(token)) {
String username = jwtUtils.getUsernameFromToken(token);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterChain.doFilter(request, response);
}
private String getTokenFromRequest(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
return null;
}
}用户认证服务
UserDetailsService实现
@Service
@RequiredArgsConstructor
public class CustomUserDetailsService implements UserDetailsService {
private final UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("用户不存在"));
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(),
user.getEnabled(),
true, true, true,
getAuthorities(user.getRoles())
);
}
private Collection<? extends GrantedAuthority> getAuthorities(Set<Role> roles) {
return roles.stream()
.map(role -> new SimpleGrantedAuthority("ROLE_" + role.getName()))
.collect(Collectors.toList());
}
}认证控制器
@RestController
@RequestMapping("/api/auth")
@RequiredArgsConstructor
public class AuthController {
private final AuthenticationManager authenticationManager;
private final JwtUtils jwtUtils;
private final UserDetailsService userDetailsService;
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody LoginRequest request) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
request.getUsername(),
request.getPassword()
)
);
SecurityContextHolder.getContext().setAuthentication(authentication);
String token = jwtUtils.generateToken((UserDetails) authentication.getPrincipal());
return ResponseEntity.ok(new JwtResponse(token));
}
@PostMapping("/register")
public ResponseEntity<?> register(@RequestBody RegisterRequest request) {
// 注册逻辑...
return ResponseEntity.ok("注册成功");
}
}方法级安全
启用方法安全
@Configuration
@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig {
}使用注解
@RestController
@RequestMapping("/api/users")
public class UserController {
// 需要认证
@PreAuthorize("isAuthenticated()")
@GetMapping("/me")
public User getCurrentUser() {
return userService.getCurrentUser();
}
// 需要ADMIN角色
@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/admin/all")
public List<User> getAllUsers() {
return userService.findAll();
}
// 需要特定权限
@PreAuthorize("hasAuthority('user:write')")
@PostMapping
public User createUser(@RequestBody UserDTO dto) {
return userService.create(dto);
}
// 复杂表达式
@PreAuthorize("hasRole('ADMIN') or #id == authentication.principal.id")
@PutMapping("/{id}")
public User update(@PathVariable Long id, @RequestBody UserDTO dto) {
return userService.update(id, dto);
}
// 方法调用后校验
@PostAuthorize("returnObject.username == authentication.principal.username")
@GetMapping("/{id}")
public User getById(@PathVariable Long id) {
return userService.findById(id);
}
// 过滤返回结果
@PostFilter("filterObject.owner == authentication.principal.username")
@GetMapping("/my")
public List<User> getMyUsers() {
return userService.findAll();
}
}CORS配置
@Configuration
public class CorsConfig {
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(List.of("https://example.com"));
configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
configuration.setAllowedHeaders(List.of("*"));
configuration.setAllowCredentials(true);
configuration.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}OAuth2
资源服务器配置
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://auth.example.com@Configuration
@EnableWebSecurity
public class OAuth2ResourceServerConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
return http.build();
}
}小结
| 组件 | 说明 |
|---|---|
| SecurityFilterChain | 安全过滤器链 |
| UserDetailsService | 用户详情服务 |
| PasswordEncoder | 密码编码器 |
| JWT | 无状态Token认证 |
| @PreAuthorize | 方法级授权 |
| OAuth2 | 开放授权 |

