Contents
see List작성일 2025. 11. 30.
Spring Security 6 JWT 인증 구현
Spring Security 6에서 JWT 토큰 기반 인증을 구현하는 방법입니다.
의존성
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.12.3</version>
</dependency>Security 설정 (Spring Security 6)
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.sessionManagement(session ->
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/auth/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated())
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}JWT 유틸리티
@Component
public class JwtUtil {
private final String SECRET = "your-secret-key";
private final long EXPIRATION = 86400000; // 24시간
public String generateToken(UserDetails user) {
return Jwts.builder()
.subject(user.getUsername())
.issuedAt(new Date())
.expiration(new Date(System.currentTimeMillis() + EXPIRATION))
.signWith(Keys.hmacShaKeyFor(SECRET.getBytes()))
.compact();
}
public String extractUsername(String token) {
return Jwts.parser()
.verifyWith(Keys.hmacShaKeyFor(SECRET.getBytes()))
.build()
.parseSignedClaims(token)
.getPayload()
.getSubject();
}
public boolean isTokenValid(String token, UserDetails user) {
String username = extractUsername(token);
return username.equals(user.getUsername()) && !isTokenExpired(token);
}
}JWT 필터
@Component
public class JwtAuthFilter extends OncePerRequestFilter {
@Autowired
private JwtUtil jwtUtil;
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain chain) {
String header = request.getHeader("Authorization");
if (header != null && header.startsWith("Bearer ")) {
String token = header.substring(7);
String username = jwtUtil.extractUsername(token);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails user = userDetailsService.loadUserByUsername(username);
if (jwtUtil.isTokenValid(token, user)) {
UsernamePasswordAuthenticationToken auth =
new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(auth);
}
}
}
chain.doFilter(request, response);
}
}로그인 컨트롤러
@RestController
@RequestMapping("/auth")
public class AuthController {
@Autowired
private AuthenticationManager authManager;
@Autowired
private JwtUtil jwtUtil;
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody LoginRequest request) {
Authentication auth = authManager.authenticate(
new UsernamePasswordAuthenticationToken(
request.getUsername(), request.getPassword()));
UserDetails user = (UserDetails) auth.getPrincipal();
String token = jwtUtil.generateToken(user);
return ResponseEntity.ok(Map.of("token", token));
}
}Refresh Token 구현
// Access Token: 15분
// Refresh Token: 7일
@PostMapping("/refresh")
public ResponseEntity<?> refresh(@RequestBody RefreshRequest request) {
String refreshToken = request.getRefreshToken();
if (jwtUtil.isRefreshTokenValid(refreshToken)) {
String username = jwtUtil.extractUsername(refreshToken);
UserDetails user = userDetailsService.loadUserByUsername(username);
String newAccessToken = jwtUtil.generateAccessToken(user);
return ResponseEntity.ok(Map.of("accessToken", newAccessToken));
}
return ResponseEntity.status(401).build();
}spring
| No | 작성일 | Title |
|---|---|---|
| 3360 | 2026. 08. 15. | Spring Boot Actuator와 Micrometer로 장애 징후를 먼저 찾는 운영 모니터링 구성 |
| 3328 | 2026. 08. 06. | Spring Boot 예외 처리 표준화 가이드: ProblemDetail로 일관된 API 오류 응답 만들기 |
| 3296 | 2026. 07. 29. | Spring Boot 로그인 API 보안 설계: 세션 없이 JWT를 안전하게 검증하는 방법 |
| 3265 | 2026. 07. 21. | Spring Boot API 장애 원인 빨리 찾기: Actuator와 Micrometer 관측성 구성 가이드 |
| 3238 | 2026. 07. 13. | Spring Boot 안정적인 외부 API 연동: WebClient·Circuit Breaker·Retry를 함께 운영하는 실전 가이드 |
| 3182 | 2026. 07. 04. | Spring Boot 무중단 배포를 위한 Graceful Shutdown과 Readiness Probe 설정 |
| 3137 | 2026. 06. 26. | Spring Security API 권한 설계: 공개 엔드포인트와 관리자 기능을 분리하는 실전 기준 |
| 3081 | 2026. 06. 18. | Spring Boot API 장애 추적을 위한 요청 ID와 관측 로그 설계 |
| 2992 | 2026. 06. 10. | Spring Boot 무중단 배포를 위한 준비 상태 점검과 종료 처리 설계 |
| 2935 | 2026. 06. 02. | Spring Boot Redis 캐시 운영 가이드: TTL, 무효화, 캐시 스탬피드 방지 설계 |