From 063bd7cc74d5ce9b175d7a084b9aacc1ef009743 Mon Sep 17 00:00:00 2001 From: sohot8653 Date: Mon, 1 Sep 2025 14:17:06 +0900 Subject: [PATCH] =?UTF-8?q?[JWT=20=EA=B0=9C=EC=84=A0]=20MemberDto=EC=9D=98?= =?UTF-8?q?=20=EA=B6=8C=ED=95=9C=20=EB=B0=98=ED=99=98=20=EB=B0=A9=EC=8B=9D?= =?UTF-8?q?=EC=9D=84=20=EC=88=98=EC=A0=95=ED=95=98=EA=B3=A0,=20JwtTokenIss?= =?UTF-8?q?uanceFilter=20=EB=B0=8F=20JwtTokenValidationFilter=EC=97=90?= =?UTF-8?q?=EC=84=9C=20Access=20Token=20=EC=83=9D=EC=84=B1=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=EC=9D=84=20=EA=B0=9C=EC=84=A0=ED=95=98=EC=97=AC=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=EC=9E=90=20=EC=A0=95=EB=B3=B4=EB=A5=BC=20?= =?UTF-8?q?=ED=8F=AC=ED=95=A8=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD.=20JwtUtils=EC=97=90=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=EC=84=B8=EB=B6=80=EC=A0=95=EB=B3=B4=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=EC=9D=84=20=EC=9C=84=ED=95=9C=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/base/member/dto/MemberDto.java | 2 +- .../global/filter/JwtTokenIssuanceFilter.java | 2 +- .../filter/JwtTokenValidationFilter.java | 10 +++-- .../bio_backend/global/utils/JwtUtils.java | 40 +++++++++++++++++-- 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/bio/bio_backend/domain/base/member/dto/MemberDto.java b/src/main/java/com/bio/bio_backend/domain/base/member/dto/MemberDto.java index 178304f..8e072b3 100644 --- a/src/main/java/com/bio/bio_backend/domain/base/member/dto/MemberDto.java +++ b/src/main/java/com/bio/bio_backend/domain/base/member/dto/MemberDto.java @@ -32,7 +32,7 @@ public class MemberDto implements UserDetails { @Override public Collection getAuthorities() { - return Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")); + return Collections.emptyList(); } @Override diff --git a/src/main/java/com/bio/bio_backend/global/filter/JwtTokenIssuanceFilter.java b/src/main/java/com/bio/bio_backend/global/filter/JwtTokenIssuanceFilter.java index 1f637f3..4c67fd1 100644 --- a/src/main/java/com/bio/bio_backend/global/filter/JwtTokenIssuanceFilter.java +++ b/src/main/java/com/bio/bio_backend/global/filter/JwtTokenIssuanceFilter.java @@ -66,7 +66,7 @@ public class JwtTokenIssuanceFilter extends UsernamePasswordAuthenticationFilter MemberDto member = (MemberDto) userDetails; // 토큰 생성 - String accessToken = jwtUtils.createAccessToken(member.getUserId()); + String accessToken = jwtUtils.createAccessToken(member.getOid(), member.getUserId(), member.getName()); String refreshToken = jwtUtils.createRefreshToken(member.getUserId(), httpUtils.getClientIp()); member.setRefreshToken(refreshToken); diff --git a/src/main/java/com/bio/bio_backend/global/filter/JwtTokenValidationFilter.java b/src/main/java/com/bio/bio_backend/global/filter/JwtTokenValidationFilter.java index 4149517..f7b2386 100644 --- a/src/main/java/com/bio/bio_backend/global/filter/JwtTokenValidationFilter.java +++ b/src/main/java/com/bio/bio_backend/global/filter/JwtTokenValidationFilter.java @@ -52,13 +52,13 @@ public class JwtTokenValidationFilter extends OncePerRequestFilter { log.debug("JWT 토큰 검증 필터 실행 - URI: {}", request.getRequestURI()); - String accessToken = jwtUtils.extractAccessJwtFromRequest(request); + String accessToken = jwtUtils.extractAccessJwtFromCookie(request); String refreshToken = jwtUtils.extractRefreshJwtFromCookie(request); // Access Token이 있고 유효한 경우 if (accessToken != null && jwtUtils.validateAccessToken(accessToken)) { String username = jwtUtils.extractUsername(accessToken); - UserDetails userDetails = memberService.loadUserByUsername(username); + UserDetails userDetails = jwtUtils.createUserDetailsFromToken(accessToken); if (userDetails != null) { UsernamePasswordAuthenticationToken authentication = @@ -94,7 +94,11 @@ public class JwtTokenValidationFilter extends OncePerRequestFilter { UserDetails userDetails = memberService.loadUserByUsername(username); // 새로운 Access Token 생성 - String newAccessToken = jwtUtils.createAccessToken(username); + String newAccessToken = jwtUtils.createAccessToken( + ((MemberDto) userDetails).getOid(), + userDetails.getUsername(), + ((MemberDto) userDetails).getName() + ); // 새로운 Access Token을 쿠키에 설정 jwtUtils.setAccessTokenCookie(response, newAccessToken); diff --git a/src/main/java/com/bio/bio_backend/global/utils/JwtUtils.java b/src/main/java/com/bio/bio_backend/global/utils/JwtUtils.java index 3b5f64c..1674582 100644 --- a/src/main/java/com/bio/bio_backend/global/utils/JwtUtils.java +++ b/src/main/java/com/bio/bio_backend/global/utils/JwtUtils.java @@ -8,10 +8,12 @@ import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import com.bio.bio_backend.domain.base.member.service.MemberService; +import com.bio.bio_backend.domain.base.member.dto.MemberDto; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.env.Environment; +import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Component; import javax.crypto.SecretKey; @@ -44,6 +46,18 @@ public class JwtUtils { .compact(); } + // Token 생성 (사용자 정보 포함) + public String generateToken(Long oid, String username, String name, long expirationTime) { + return Jwts.builder() + .subject(username) + .claim("oid", oid) + .claim("name", name) + .issuedAt(new Date(System.currentTimeMillis())) + .expiration(new Date(System.currentTimeMillis() + expirationTime)) + .signWith(getSigningKey()) + .compact(); + } + // Token 생성(IP 정보 포함) public String generateToken(String username, String clientIp, long expirationTime) { return Jwts.builder() @@ -56,11 +70,12 @@ public class JwtUtils { } // Access Token 생성 - public String createAccessToken(String username) { + public String createAccessToken(Long oid, String username, String name) { long expirationTime = Long.parseLong(Objects.requireNonNull(env.getProperty("token.expiration_time_access"))); - return generateToken(username, expirationTime); + return generateToken(oid, username, name, expirationTime); } + // Refresh Token 생성 시 IP 정보 포함 public String createRefreshToken(String username, String clientIp) { long expirationTime = Long.parseLong(Objects.requireNonNull(env.getProperty("token.expiration_time_refresh"))); @@ -131,7 +146,7 @@ public class JwtUtils { } // Access Token을 쿠키에서 추출 - public String extractAccessJwtFromRequest(HttpServletRequest request) { + public String extractAccessJwtFromCookie(HttpServletRequest request) { if (request.getCookies() != null) { for (Cookie cookie : request.getCookies()) { if ("AccessToken".equals(cookie.getName())) { @@ -191,4 +206,23 @@ public class JwtUtils { cookie.setMaxAge(maxAge); response.addCookie(cookie); } + + public UserDetails createUserDetailsFromToken(String accessToken) { + try { + Claims claims = extractAllClaims(accessToken); + String username = claims.getSubject(); + Long oid = claims.get("oid", Long.class); + String name = claims.get("name", String.class); + + // 토큰에서 직접 UserDetails 생성 (DB 조회 없음) + return MemberDto.builder() + .oid(oid) + .userId(username) + .name(name) + .build(); + } catch (Exception e) { + log.debug("토큰에서 UserDetails 생성 실패: {}", e.getMessage()); + return null; + } + } }