Fix : 수정
This commit is contained in:
parent
185eafebe6
commit
ef87bfbb0b
@ -1,12 +1,12 @@
|
|||||||
package com.ktds.hi.member.config;
|
package com.ktds.hi.member.config;
|
||||||
|
|
||||||
import com.ktds.hi.member.service.JwtTokenProvider;
|
import com.ktds.hi.member.service.JwtTokenProvider;
|
||||||
import com.ktds.hi.member.service.AuthService;
|
|
||||||
import jakarta.servlet.FilterChain;
|
import jakarta.servlet.FilterChain;
|
||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
@ -19,20 +19,26 @@ import java.io.IOException;
|
|||||||
* 요청 헤더의 JWT 토큰을 검증하고 인증 정보를 설정
|
* 요청 헤더의 JWT 토큰을 검증하고 인증 정보를 설정
|
||||||
*/
|
*/
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
private final JwtTokenProvider tokenProvider;
|
private final JwtTokenProvider tokenProvider;
|
||||||
private final AuthService authService;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
|
||||||
FilterChain filterChain) throws ServletException, IOException {
|
FilterChain filterChain) throws ServletException, IOException {
|
||||||
|
|
||||||
String token = resolveToken(request);
|
try {
|
||||||
|
String token = resolveToken(request);
|
||||||
|
|
||||||
if (StringUtils.hasText(token) && tokenProvider.validateToken(token)) {
|
if (StringUtils.hasText(token) && tokenProvider.validateToken(token)) {
|
||||||
Authentication authentication = tokenProvider.getAuthentication(token);
|
Authentication authentication = tokenProvider.getAuthentication(token);
|
||||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||||
|
log.debug("JWT 토큰 인증 성공: {}", authentication.getName());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("JWT 토큰 인증 실패", e);
|
||||||
|
SecurityContextHolder.clearContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
filterChain.doFilter(request, response);
|
filterChain.doFilter(request, response);
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
package com.ktds.hi.member.config;
|
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.JwtTokenProvider;
|
||||||
import com.ktds.hi.member.service.AuthService;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
@ -27,7 +28,6 @@ public class SecurityConfig {
|
|||||||
|
|
||||||
@Qualifier("memberJwtTokenProvider")
|
@Qualifier("memberJwtTokenProvider")
|
||||||
private final JwtTokenProvider jwtTokenProvider;
|
private final JwtTokenProvider jwtTokenProvider;
|
||||||
private final AuthService authService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 보안 필터 체인 설정
|
* 보안 필터 체인 설정
|
||||||
@ -40,16 +40,23 @@ public class SecurityConfig {
|
|||||||
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||||
.authorizeHttpRequests(authz -> authz
|
.authorizeHttpRequests(authz -> authz
|
||||||
.requestMatchers("/api/auth/**", "/api/members/register").permitAll()
|
.requestMatchers("/api/auth/**", "/api/members/register").permitAll()
|
||||||
.requestMatchers("/swagger-ui/**", "/api-docs/**").permitAll()
|
.requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll()
|
||||||
.requestMatchers("/actuator/**").permitAll()
|
.requestMatchers("/actuator/**").permitAll()
|
||||||
.anyRequest().authenticated()
|
.anyRequest().authenticated()
|
||||||
)
|
)
|
||||||
.addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider, authService),
|
.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
|
||||||
UsernamePasswordAuthenticationFilter.class);
|
|
||||||
|
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JWT 인증 필터 빈
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public JwtAuthenticationFilter jwtAuthenticationFilter() {
|
||||||
|
return new JwtAuthenticationFilter(jwtTokenProvider);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 비밀번호 암호화 빈
|
* 비밀번호 암호화 빈
|
||||||
*/
|
*/
|
||||||
@ -65,4 +72,45 @@ public class SecurityConfig {
|
|||||||
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
|
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
|
||||||
return config.getAuthenticationManager();
|
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();
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import java.util.Date;
|
|||||||
* JWT 토큰 프로바이더 클래스
|
* JWT 토큰 프로바이더 클래스
|
||||||
* JWT 토큰 생성, 검증, 파싱 기능을 제공
|
* JWT 토큰 생성, 검증, 파싱 기능을 제공
|
||||||
*/
|
*/
|
||||||
@Component("memberJwtTokenProvider") // 기존: @Component
|
@Component("memberJwtTokenProvider")
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class JwtTokenProvider {
|
public class JwtTokenProvider {
|
||||||
|
|
||||||
@ -25,9 +25,9 @@ public class JwtTokenProvider {
|
|||||||
private final long accessTokenExpiration;
|
private final long accessTokenExpiration;
|
||||||
private final long refreshTokenExpiration;
|
private final long refreshTokenExpiration;
|
||||||
|
|
||||||
public JwtTokenProvider(@Value("${jwt.secret}") String secret,
|
public JwtTokenProvider(@Value("${jwt.secret:mySecretKey123456789012345678901234567890}") String secret,
|
||||||
@Value("${jwt.access-token-expiration}") long accessTokenExpiration,
|
@Value("${jwt.access-token-expiration:1800000}") long accessTokenExpiration,
|
||||||
@Value("${jwt.refresh-token-expiration}") long refreshTokenExpiration) {
|
@Value("${jwt.refresh-token-expiration:604800000}") long refreshTokenExpiration) {
|
||||||
this.secretKey = Keys.hmacShaKeyFor(secret.getBytes());
|
this.secretKey = Keys.hmacShaKeyFor(secret.getBytes());
|
||||||
this.accessTokenExpiration = accessTokenExpiration;
|
this.accessTokenExpiration = accessTokenExpiration;
|
||||||
this.refreshTokenExpiration = refreshTokenExpiration;
|
this.refreshTokenExpiration = refreshTokenExpiration;
|
||||||
@ -41,12 +41,13 @@ public class JwtTokenProvider {
|
|||||||
Date expiration = new Date(now.getTime() + accessTokenExpiration);
|
Date expiration = new Date(now.getTime() + accessTokenExpiration);
|
||||||
|
|
||||||
return Jwts.builder()
|
return Jwts.builder()
|
||||||
.setSubject(memberId.toString())
|
.setSubject(memberId.toString())
|
||||||
.claim("role", role)
|
.claim("role", role)
|
||||||
.setIssuedAt(now)
|
.claim("type", "access")
|
||||||
.setExpiration(expiration)
|
.setIssuedAt(now)
|
||||||
.signWith(secretKey)
|
.setExpiration(expiration)
|
||||||
.compact();
|
.signWith(secretKey)
|
||||||
|
.compact();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,58 +58,82 @@ public class JwtTokenProvider {
|
|||||||
Date expiration = new Date(now.getTime() + refreshTokenExpiration);
|
Date expiration = new Date(now.getTime() + refreshTokenExpiration);
|
||||||
|
|
||||||
return Jwts.builder()
|
return Jwts.builder()
|
||||||
.setSubject(memberId.toString())
|
.setSubject(memberId.toString())
|
||||||
.setIssuedAt(now)
|
.claim("type", "refresh")
|
||||||
.setExpiration(expiration)
|
.setIssuedAt(now)
|
||||||
.signWith(secretKey)
|
.setExpiration(expiration)
|
||||||
.compact();
|
.signWith(secretKey)
|
||||||
|
.compact();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 토큰에서 인증 정보 추출
|
* 토큰에서 인증 정보 추출
|
||||||
*/
|
*/
|
||||||
public Authentication getAuthentication(String token) {
|
public Authentication getAuthentication(String token) {
|
||||||
Claims claims = parseClaims(token);
|
Claims claims = getClaims(token);
|
||||||
|
|
||||||
String memberId = claims.getSubject();
|
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(
|
return new UsernamePasswordAuthenticationToken(
|
||||||
memberId,
|
memberId,
|
||||||
null,
|
null,
|
||||||
Collections.singletonList(new SimpleGrantedAuthority("ROLE_" + role))
|
Collections.singletonList(authority)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 토큰에서 회원 ID 추출
|
|
||||||
*/
|
|
||||||
public Long getMemberIdFromToken(String token) {
|
|
||||||
Claims claims = parseClaims(token);
|
|
||||||
return Long.valueOf(claims.getSubject());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 토큰 유효성 검증
|
* 토큰 유효성 검증
|
||||||
*/
|
*/
|
||||||
public boolean validateToken(String token) {
|
public boolean validateToken(String token) {
|
||||||
try {
|
try {
|
||||||
parseClaims(token);
|
getClaims(token);
|
||||||
return true;
|
return true;
|
||||||
} catch (JwtException | IllegalArgumentException e) {
|
} catch (ExpiredJwtException e) {
|
||||||
log.warn("Invalid JWT token: {}", e.getMessage());
|
log.warn("JWT 토큰 만료: {}", e.getMessage());
|
||||||
return false;
|
} 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) {
|
public Long getMemberIdFromToken(String token) {
|
||||||
|
Claims claims = getClaims(token);
|
||||||
|
return Long.parseLong(claims.getSubject());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 토큰에서 클레임 추출
|
||||||
|
*/
|
||||||
|
private Claims getClaims(String token) {
|
||||||
return Jwts.parser()
|
return Jwts.parser()
|
||||||
.setSigningKey(secretKey)
|
.setSigningKey(secretKey)
|
||||||
.build()
|
.build()
|
||||||
.parseClaimsJws(token)
|
.parseClaimsJws(token)
|
||||||
.getBody();
|
.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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user