Fix : 수정
This commit is contained in:
parent
ef87bfbb0b
commit
0b78427304
@ -1,57 +1,59 @@
|
||||
package com.ktds.hi.member.config;
|
||||
|
||||
import com.ktds.hi.member.service.JwtTokenProvider;
|
||||
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;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* JWT 인증 필터 클래스
|
||||
* 요청 헤더의 JWT 토큰을 검증하고 인증 정보를 설정
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
private final JwtTokenProvider tokenProvider;
|
||||
|
||||
@Override
|
||||
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 토큰 추출
|
||||
*/
|
||||
private String resolveToken(HttpServletRequest request) {
|
||||
String bearerToken = request.getHeader("Authorization");
|
||||
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
|
||||
return bearerToken.substring(7);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// package com.ktds.hi.member.config;
|
||||
//
|
||||
//
|
||||
// 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;
|
||||
// import org.springframework.web.filter.OncePerRequestFilter;
|
||||
//
|
||||
// import java.io.IOException;
|
||||
//
|
||||
// import com.ktds.hi.common.security.JwtTokenProvider;
|
||||
//
|
||||
// /**
|
||||
// * JWT 인증 필터 클래스
|
||||
// * 요청 헤더의 JWT 토큰을 검증하고 인증 정보를 설정
|
||||
// */
|
||||
// @RequiredArgsConstructor
|
||||
// @Slf4j
|
||||
// public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
//
|
||||
// private final JwtTokenProvider tokenProvider;
|
||||
//
|
||||
// @Override
|
||||
// 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 토큰 추출
|
||||
// */
|
||||
// private String resolveToken(HttpServletRequest request) {
|
||||
// String bearerToken = request.getHeader("Authorization");
|
||||
// if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
|
||||
// return bearerToken.substring(7);
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
@ -1,8 +1,9 @@
|
||||
package com.ktds.hi.member.config;
|
||||
|
||||
|
||||
import com.ktds.hi.member.config.JwtAuthenticationFilter;
|
||||
import com.ktds.hi.member.service.JwtTokenProvider;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ktds.hi.common.security.JwtTokenProvider;
|
||||
import com.ktds.hi.common.security.JwtAuthenticationFilter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@ -26,7 +27,6 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic
|
||||
@RequiredArgsConstructor
|
||||
public class SecurityConfig {
|
||||
|
||||
@Qualifier("memberJwtTokenProvider")
|
||||
private final JwtTokenProvider jwtTokenProvider;
|
||||
|
||||
/**
|
||||
@ -54,7 +54,7 @@ public class SecurityConfig {
|
||||
*/
|
||||
@Bean
|
||||
public JwtAuthenticationFilter jwtAuthenticationFilter() {
|
||||
return new JwtAuthenticationFilter(jwtTokenProvider);
|
||||
return new JwtAuthenticationFilter(jwtTokenProvider,new ObjectMapper());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.ktds.hi.member.service;
|
||||
|
||||
import com.ktds.hi.common.security.JwtTokenProvider;
|
||||
import com.ktds.hi.member.dto.*;
|
||||
import com.ktds.hi.member.repository.entity.MemberEntity;
|
||||
import com.ktds.hi.member.repository.jpa.MemberRepository;
|
||||
@ -11,6 +12,7 @@ import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
@ -24,7 +26,6 @@ public class AuthServiceImpl implements AuthService {
|
||||
|
||||
private final MemberRepository memberRepository;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
@Qualifier("memberJwtTokenProvider")
|
||||
private final JwtTokenProvider jwtTokenProvider;
|
||||
private final SmsService smsService;
|
||||
private final RedisTemplate<String, String> redisTemplate;
|
||||
@ -41,9 +42,13 @@ public class AuthServiceImpl implements AuthService {
|
||||
}
|
||||
|
||||
// JWT 토큰 생성
|
||||
String accessToken = jwtTokenProvider.generateAccessToken(member.getId(), member.getRole());
|
||||
String refreshToken = jwtTokenProvider.generateRefreshToken(member.getId());
|
||||
|
||||
String accessToken = jwtTokenProvider.createAccessToken(
|
||||
member.getId().toString(),
|
||||
Collections.singletonList(member.getRole())
|
||||
);
|
||||
String refreshToken = jwtTokenProvider.createRefreshToken(member.getId().toString());
|
||||
|
||||
|
||||
// 리프레시 토큰 Redis 저장
|
||||
redisTemplate.opsForValue().set(
|
||||
"refresh_token:" + member.getId(),
|
||||
@ -62,10 +67,12 @@ public class AuthServiceImpl implements AuthService {
|
||||
@Override
|
||||
public void logout(LogoutRequest request) {
|
||||
// 리프레시 토큰에서 사용자 ID 추출
|
||||
Long memberId = jwtTokenProvider.getMemberIdFromToken(request.getRefreshToken());
|
||||
|
||||
// Redis에서 리프레시 토큰 삭제
|
||||
redisTemplate.delete("refresh_token:" + memberId);
|
||||
String userId = jwtTokenProvider.getUserIdFromToken(request.getRefreshToken());
|
||||
|
||||
if (userId != null) {
|
||||
// Redis에서 리프레시 토큰 삭제
|
||||
redisTemplate.delete("refresh_token:" + userId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -75,7 +82,7 @@ public class AuthServiceImpl implements AuthService {
|
||||
throw new BusinessException("유효하지 않은 리프레시 토큰입니다");
|
||||
}
|
||||
|
||||
Long memberId = jwtTokenProvider.getMemberIdFromToken(refreshToken);
|
||||
Long memberId = Long.parseLong(jwtTokenProvider.getUserIdFromToken(refreshToken));
|
||||
|
||||
// Redis에서 리프레시 토큰 확인
|
||||
String storedToken = redisTemplate.opsForValue().get("refresh_token:" + memberId);
|
||||
@ -88,8 +95,12 @@ public class AuthServiceImpl implements AuthService {
|
||||
.orElseThrow(() -> new BusinessException("존재하지 않는 사용자입니다"));
|
||||
|
||||
// 새 토큰 생성
|
||||
String newAccessToken = jwtTokenProvider.generateAccessToken(member.getId(), member.getRole());
|
||||
String newRefreshToken = jwtTokenProvider.generateRefreshToken(member.getId());
|
||||
String newAccessToken = jwtTokenProvider.createAccessToken(
|
||||
member.getId().toString(),
|
||||
Collections.singletonList(member.getRole())
|
||||
);
|
||||
|
||||
String newRefreshToken = jwtTokenProvider.createRefreshToken(member.getId().toString());
|
||||
|
||||
// 새 리프레시 토큰 Redis 저장
|
||||
redisTemplate.opsForValue().set(
|
||||
|
||||
@ -1,139 +0,0 @@
|
||||
package com.ktds.hi.member.service;
|
||||
|
||||
import io.jsonwebtoken.*;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* JWT 토큰 프로바이더 클래스
|
||||
* JWT 토큰 생성, 검증, 파싱 기능을 제공
|
||||
*/
|
||||
@Component("memberJwtTokenProvider")
|
||||
@Slf4j
|
||||
public class JwtTokenProvider {
|
||||
|
||||
private final SecretKey secretKey;
|
||||
private final long accessTokenExpiration;
|
||||
private final 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)
|
||||
.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())
|
||||
.claim("type", "refresh")
|
||||
.setIssuedAt(now)
|
||||
.setExpiration(expiration)
|
||||
.signWith(secretKey)
|
||||
.compact();
|
||||
}
|
||||
|
||||
/**
|
||||
* 토큰에서 인증 정보 추출
|
||||
*/
|
||||
public Authentication getAuthentication(String token) {
|
||||
Claims claims = getClaims(token);
|
||||
String memberId = claims.getSubject();
|
||||
String role = (String) claims.get("role");
|
||||
|
||||
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_" + (role != null ? role : "USER"));
|
||||
|
||||
return new UsernamePasswordAuthenticationToken(
|
||||
memberId,
|
||||
null,
|
||||
Collections.singletonList(authority)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 토큰 유효성 검증
|
||||
*/
|
||||
public boolean validateToken(String token) {
|
||||
try {
|
||||
getClaims(token);
|
||||
return true;
|
||||
} 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 추출
|
||||
*/
|
||||
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());
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,11 @@
|
||||
dependencies {
|
||||
implementation project(':common')
|
||||
|
||||
// File Storage
|
||||
|
||||
// AI and Location Services
|
||||
implementation 'org.springframework.boot:spring-boot-starter-webflux'
|
||||
}
|
||||
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:4.1.0'
|
||||
|
||||
|
||||
implementation 'org.springframework.cloud:spring-cloud-starter-circuitbreaker-resilience4j:'
|
||||
implementation 'org.springframework.cloud:spring-cloud-starter-loadbalancer:latest'
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user