From 921e7a8e5b0406a28186a4296ca2675242037e57 Mon Sep 17 00:00:00 2001 From: Limwngur Date: Wed, 26 Jul 2023 09:07:19 +0900 Subject: [PATCH] =?UTF-8?q?=E2=9A=BDfeat#23:=20[Auth2]=20refresh=20Token?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1,=20=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85,?= =?UTF-8?q?=20AccessToken=EC=9E=AC=EB=B0=9C=EA=B8=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/contorller/UserController.java | 23 +++++++-- .../user/repository/UserRepository.java | 2 + .../domain/user/service/UserService.java | 47 ++++++++++++++++--- .../global/util/JwtTokenProvider.java | 13 +++++ .../security/JwtTokenFilter.java | 17 ++++++- 5 files changed, 89 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/contorller/UserController.java b/src/main/java/com/umc/DongnaeFriend/domain/user/contorller/UserController.java index b5b9805..d8d0374 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/user/contorller/UserController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/contorller/UserController.java @@ -6,8 +6,9 @@ import com.umc.DongnaeFriend.global.exception.CustomException; import com.umc.DongnaeFriend.global.exception.ErrorCode; import com.umc.DongnaeFriend.global.util.JwtTokenProvider; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; +import org.springframework.http.*; import org.springframework.web.bind.annotation.*; import java.io.IOException; @@ -15,6 +16,7 @@ @RestController @RequestMapping("/user") +@Slf4j public class UserController { @Autowired @@ -25,6 +27,8 @@ public class UserController { JwtTokenProvider jwtTokenProvider; + + /** * 유저 로그인 / 회원가입 * 인증 절차 @@ -32,6 +36,7 @@ public class UserController { @PostMapping("/login") public ResponseEntity userLogin(@RequestBody UserDto.Request request) { try { + log.info("userLogin 진입"); //사용자 정보 가져오기 HashMap userInfo = kakaoService.getUserInfo(request.getAccessToken()); @@ -39,8 +44,8 @@ public ResponseEntity userLogin(@RequestBody UserDto.Request request) { userService.userValidation(userInfo); //토큰 생성 - String access_token = jwtTokenProvider.createAccessToken((Long) userInfo.get("usreId")); - + String access_token = jwtTokenProvider.createAccessToken((Long) userInfo.get("userId")); + log.info("access_token : {}", access_token); return ResponseEntity.ok(access_token); } catch (IOException e) { @@ -49,8 +54,16 @@ public ResponseEntity userLogin(@RequestBody UserDto.Request request) { } @PostMapping("/user/reissuance") - public ResponseEntity reiussnaceToken(String access_oto) { - return null; + public ResponseEntity reiussnaceToken(String refreshToken) { + try { + + //토큰 재발급 + String access_token = userService.createAccessTokenFromRefreshToken(refreshToken); + return ResponseEntity.ok(access_token); + } catch (Exception e) { + // RefreshToken만료 + throw new CustomException(ErrorCode.INVALID_REFRESH_TOKEN); + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/repository/UserRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/user/repository/UserRepository.java index 869602d..5edd72b 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/user/repository/UserRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/repository/UserRepository.java @@ -8,4 +8,6 @@ public interface UserRepository extends JpaRepository { Optional findById(Long id); + + Optional findByRefreshToken(String refresh_token); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java b/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java index 3e16261..3f7e6f1 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java @@ -3,17 +3,21 @@ import com.umc.DongnaeFriend.domain.type.Age; import com.umc.DongnaeFriend.domain.type.Gender; import com.umc.DongnaeFriend.domain.type.YesNo; -import com.umc.DongnaeFriend.domain.user.dto.UserDto; import com.umc.DongnaeFriend.domain.user.entity.User; import com.umc.DongnaeFriend.domain.user.repository.UserRepository; +import com.umc.DongnaeFriend.global.exception.CustomException; +import com.umc.DongnaeFriend.global.exception.ErrorCode; +import com.umc.DongnaeFriend.global.util.JwtTokenProvider; +import com.umc.DongnaeFriend.global.util.JwtUtil; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.io.IOException; import java.util.HashMap; import java.util.Optional; @Service +@Slf4j public class UserService { @Autowired @@ -21,8 +25,11 @@ public class UserService { KakaoService kakaoService; + JwtTokenProvider jwtTokenProvider; + public void userValidation(HashMap userInfo) { Optional user= userRepository.findById((Long) userInfo.get("userId")); + if (user.isEmpty()) { userRegister(userInfo); } @@ -37,23 +44,51 @@ public void userRegister(HashMap userInfo) { String email = userInfo.get("email").toString(); Optional gender = Optional.ofNullable(userInfo.get("gender").toString()); + String strGender = ""; + log.info("Gender : {}", gender.get()); + if(gender.get()=="F"){ + strGender="여성"; + }else { + strGender = "남성"; + } + log.info("strGender : {}", strGender); + Optional age = Optional.ofNullable(userInfo.get("age").toString()); + String[] ageRange = age.get().split("-"); + // refreshToken userId를 claim 으로 생성 뒤, User의 필드에 넣고 User를 저장 + String refresh_Token = jwtTokenProvider.createRefreshToken((Long) userInfo.get("usreId")); userRepository.save( User.builder() .nickname(nickName) .email(email) - //TODO : Gender 결정 - .gender(Gender.FEMALE) - //TODO : Age 결정 - .age(Age.AGE10) + //TODO : Gender 결정[O] + .gender(Gender.valueOf(strGender)) + //TODO : Age 결정[O] + .age(Age.valueOf(ageRange[0]+"대")) .townCert(YesNo.NO) .townCertCnt(0) .infoCert(YesNo.NO) + .refreshToken(refresh_Token) .build() ); } + + // RefreshToken으로 AccessToken 재발급 + public String createAccessTokenFromRefreshToken(String refreshToken) { + String accessToken = ""; + + // 전달받은 RefreshToken 정보로 사용자 조회(유효하지 않은 토큰일 시, 예외 발생) + Optional userByRefreshToken =Optional.ofNullable(userRepository.findByRefreshToken(refreshToken) + .orElseThrow(()-> new CustomException(ErrorCode.INVALID_REFRESH_TOKEN,"해당 refreshToken 이 존재하지 않음"))); + + // AccessToken 재발행 + accessToken = jwtTokenProvider.createAccessToken(userByRefreshToken.get().getId()); + log.info("AcessToken 재발행 성공"); + + return accessToken; + } } diff --git a/src/main/java/com/umc/DongnaeFriend/global/util/JwtTokenProvider.java b/src/main/java/com/umc/DongnaeFriend/global/util/JwtTokenProvider.java index 427a8bd..85fd74b 100644 --- a/src/main/java/com/umc/DongnaeFriend/global/util/JwtTokenProvider.java +++ b/src/main/java/com/umc/DongnaeFriend/global/util/JwtTokenProvider.java @@ -7,6 +7,7 @@ import org.springframework.security.core.Authentication; import org.springframework.stereotype.Component; +import javax.persistence.Id; import java.util.Date; import static com.umc.DongnaeFriend.config.JwtConfig.SECRET_KEY; @@ -46,6 +47,18 @@ public String createAccessToken(Long userId) { .compact(); } + // RefreshToken 생성 + public String createRefreshToken(Long userId) { + Date now = new Date(); + Date validity = new Date(now.getTime() + REFRESH_TOKEN_EXPIRE_LENGTH); + + return Jwts.builder() + .signWith(SignatureAlgorithm.ES512, String.valueOf(SECRET_KEY)) + .claim("userId", userId) + .setIssuedAt(now) + .setExpiration(validity) + .compact(); + } diff --git a/src/main/java/com/umc/DongnaeFriend/security/JwtTokenFilter.java b/src/main/java/com/umc/DongnaeFriend/security/JwtTokenFilter.java index df0fd76..76834db 100644 --- a/src/main/java/com/umc/DongnaeFriend/security/JwtTokenFilter.java +++ b/src/main/java/com/umc/DongnaeFriend/security/JwtTokenFilter.java @@ -1,6 +1,8 @@ package com.umc.DongnaeFriend.security; import com.umc.DongnaeFriend.global.util.JwtUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.filter.OncePerRequestFilter; @@ -11,20 +13,27 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; +@Configuration +@Slf4j public class JwtTokenFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + + log.info("JwtTOkenFilter 진입"); + // Request Header에서 JWT 토큰 가져오기 String authorizationHeader = request.getHeader("Authorization"); + log.info("authorizationHeader : {}",authorizationHeader); - // JWT 토큰이 "Bearer "로 시작하는지 확인하고 토큰 추출 + //🛑 첫 로그인 시에도 이곳에서 걸리기 때문에 로그인이 안됨.(null) if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { String token = authorizationHeader.substring(7); - + log.info("token : {}",token); try { // JWT 토큰 검증 JwtUtil.validateToken(token); + log.info("JWT 토큰 검증완료"); // JWT 토큰에서 사용자 정보 추출 (예: 사용자 ID) Long userId = JwtUtil.getUserIdFromToken(token); @@ -35,7 +44,11 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse // SecurityContextHolder에 인증 객체 저장 SecurityContextHolder.getContext().setAuthentication(authenticationToken); + + } catch (Exception e) { + log.info("예외발생"); + // JWT 토큰 검증 실패 시, 인증 객체를 null로 설정 SecurityContextHolder.clearContext(); }