Fix : 수정

This commit is contained in:
lsh9672 2025-06-12 16:57:34 +09:00
parent 185eafebe6
commit ef87bfbb0b
3 changed files with 154 additions and 75 deletions

View File

@ -1,12 +1,12 @@
package com.ktds.hi.member.config;
import com.ktds.hi.member.service.JwtTokenProvider;
import com.ktds.hi.member.service.AuthService;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;
@ -19,25 +19,31 @@ import java.io.IOException;
* 요청 헤더의 JWT 토큰을 검증하고 인증 정보를 설정
*/
@RequiredArgsConstructor
@Slf4j
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtTokenProvider tokenProvider;
private final AuthService authService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
String token = resolveToken(request);
if (StringUtils.hasText(token) && tokenProvider.validateToken(token)) {
Authentication authentication = tokenProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
try {
String token = resolveToken(request);
if (StringUtils.hasText(token) && tokenProvider.validateToken(token)) {
Authentication authentication = tokenProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
log.debug("JWT 토큰 인증 성공: {}", authentication.getName());
}
} catch (Exception e) {
log.error("JWT 토큰 인증 실패", e);
SecurityContextHolder.clearContext();
}
filterChain.doFilter(request, response);
}
/**
* 요청 헤더에서 JWT 토큰 추출
*/
@ -48,4 +54,4 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
}
return null;
}
}
}

View File

@ -1,7 +1,8 @@
package com.ktds.hi.member.config;
import com.ktds.hi.member.config.JwtAuthenticationFilter;
import com.ktds.hi.member.service.JwtTokenProvider;
import com.ktds.hi.member.service.AuthService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
@ -27,8 +28,7 @@ public class SecurityConfig {
@Qualifier("memberJwtTokenProvider")
private final JwtTokenProvider jwtTokenProvider;
private final AuthService authService;
/**
* 보안 필터 체인 설정
* JWT 인증 방식을 사용하고 세션은 무상태로 관리
@ -40,16 +40,23 @@ public class SecurityConfig {
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(authz -> authz
.requestMatchers("/api/auth/**", "/api/members/register").permitAll()
.requestMatchers("/swagger-ui/**", "/api-docs/**").permitAll()
.requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll()
.requestMatchers("/actuator/**").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider, authService),
UsernamePasswordAuthenticationFilter.class);
.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
/**
* JWT 인증 필터
*/
@Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter(jwtTokenProvider);
}
/**
* 비밀번호 암호화
*/
@ -57,7 +64,7 @@ public class SecurityConfig {
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 인증 매니저
*/
@ -65,4 +72,45 @@ public class SecurityConfig {
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
return config.getAuthenticationManager();
}
// @Qualifier("memberJwtTokenProvider")
// private final JwtTokenProvider jwtTokenProvider;
// private final AuthService authService;
//
// /**
// * 보안 필터 체인 설정
// * JWT 인증 방식을 사용하고 세션은 무상태로 관리
// */
// @Bean
// public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// http
// .csrf(csrf -> csrf.disable())
// .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
// .authorizeHttpRequests(authz -> authz
// .requestMatchers("/api/auth/**", "/api/members/register").permitAll()
// .requestMatchers("/swagger-ui/**", "/api-docs/**").permitAll()
// .requestMatchers("/actuator/**").permitAll()
// .anyRequest().authenticated()
// )
// .addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider, authService),
// UsernamePasswordAuthenticationFilter.class);
//
// return http.build();
// }
//
// /**
// * 비밀번호 암호화
// */
// @Bean
// public PasswordEncoder passwordEncoder() {
// return new BCryptPasswordEncoder();
// }
//
// /**
// * 인증 매니저
// */
// @Bean
// public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
// return config.getAuthenticationManager();
// }
}

View File

@ -17,98 +17,123 @@ import java.util.Date;
* JWT 토큰 프로바이더 클래스
* JWT 토큰 생성, 검증, 파싱 기능을 제공
*/
@Component("memberJwtTokenProvider") // 기존: @Component
@Component("memberJwtTokenProvider")
@Slf4j
public class JwtTokenProvider {
private final SecretKey secretKey;
private final long accessTokenExpiration;
private final long refreshTokenExpiration;
public JwtTokenProvider(@Value("${jwt.secret}") String secret,
@Value("${jwt.access-token-expiration}") long accessTokenExpiration,
@Value("${jwt.refresh-token-expiration}") long refreshTokenExpiration) {
public JwtTokenProvider(@Value("${jwt.secret:mySecretKey123456789012345678901234567890}") String secret,
@Value("${jwt.access-token-expiration:1800000}") long accessTokenExpiration,
@Value("${jwt.refresh-token-expiration:604800000}") long refreshTokenExpiration) {
this.secretKey = Keys.hmacShaKeyFor(secret.getBytes());
this.accessTokenExpiration = accessTokenExpiration;
this.refreshTokenExpiration = refreshTokenExpiration;
}
/**
* 액세스 토큰 생성
*/
public String generateAccessToken(Long memberId, String role) {
Date now = new Date();
Date expiration = new Date(now.getTime() + accessTokenExpiration);
return Jwts.builder()
.setSubject(memberId.toString())
.claim("role", role)
.setIssuedAt(now)
.setExpiration(expiration)
.signWith(secretKey)
.compact();
.setSubject(memberId.toString())
.claim("role", role)
.claim("type", "access")
.setIssuedAt(now)
.setExpiration(expiration)
.signWith(secretKey)
.compact();
}
/**
* 리프레시 토큰 생성
*/
public String generateRefreshToken(Long memberId) {
Date now = new Date();
Date expiration = new Date(now.getTime() + refreshTokenExpiration);
return Jwts.builder()
.setSubject(memberId.toString())
.setIssuedAt(now)
.setExpiration(expiration)
.signWith(secretKey)
.compact();
.setSubject(memberId.toString())
.claim("type", "refresh")
.setIssuedAt(now)
.setExpiration(expiration)
.signWith(secretKey)
.compact();
}
/**
* 토큰에서 인증 정보 추출
*/
public Authentication getAuthentication(String token) {
Claims claims = parseClaims(token);
Claims claims = getClaims(token);
String memberId = claims.getSubject();
String role = claims.get("role", String.class);
String role = (String) claims.get("role");
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_" + (role != null ? role : "USER"));
return new UsernamePasswordAuthenticationToken(
memberId,
null,
Collections.singletonList(new SimpleGrantedAuthority("ROLE_" + role))
memberId,
null,
Collections.singletonList(authority)
);
}
/**
* 토큰에서 회원 ID 추출
*/
public Long getMemberIdFromToken(String token) {
Claims claims = parseClaims(token);
return Long.valueOf(claims.getSubject());
}
/**
* 토큰 유효성 검증
*/
public boolean validateToken(String token) {
try {
parseClaims(token);
getClaims(token);
return true;
} catch (JwtException | IllegalArgumentException e) {
log.warn("Invalid JWT token: {}", e.getMessage());
return false;
} catch (ExpiredJwtException e) {
log.warn("JWT 토큰 만료: {}", e.getMessage());
} catch (UnsupportedJwtException e) {
log.warn("지원되지 않는 JWT 토큰: {}", e.getMessage());
} catch (MalformedJwtException e) {
log.warn("잘못된 형식의 JWT 토큰: {}", e.getMessage());
} catch (SecurityException | IllegalArgumentException e) {
log.warn("JWT 토큰 검증 실패: {}", e.getMessage());
}
return false;
}
/**
* 토큰 파싱
* 토큰에서 회원 ID 추출
*/
private Claims parseClaims(String token) {
return Jwts.parser()
.setSigningKey(secretKey)
.build()
.parseClaimsJws(token)
.getBody();
public Long getMemberIdFromToken(String token) {
Claims claims = getClaims(token);
return Long.parseLong(claims.getSubject());
}
}
/**
* 토큰에서 클레임 추출
*/
private Claims getClaims(String token) {
return Jwts.parser()
.setSigningKey(secretKey)
.build()
.parseClaimsJws(token)
.getBody();
}
/**
* 토큰 만료 시간 조회
*/
public Date getExpirationDateFromToken(String token) {
Claims claims = getClaims(token);
return claims.getExpiration();
}
/**
* 토큰이 만료되었는지 확인
*/
public boolean isTokenExpired(String token) {
Date expiration = getExpirationDateFromToken(token);
return expiration.before(new Date());
}
}