Skip to content

Commit

Permalink
♻️ Refactor: jwt 유효기간 변경 및 Refresh Token 쿠키로 전송 기능 변경
Browse files Browse the repository at this point in the history
  • Loading branch information
hyoungj00n committed May 10, 2024
1 parent a88728c commit c77f16d
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ public enum ErrorStatus implements BaseErrorCode {
MEMBER_NOT_OWNER(HttpStatus.NOT_ACCEPTABLE, "MEMBER4011", "해당 회원이 아닙니다."),
MEMBER_CONTACT_NOT_FOUND(HttpStatus.NOT_FOUND,"MEMBER4012", "연락 가능 시간을 조회할 수 없습니다."),
MEMBER_EMAIL_DUPLICATED(HttpStatus.BAD_REQUEST, "MEMBER4013", "중복된 이메일입니다."),
MEMBER_EMAIL_INCORRECT(HttpStatus.BAD_REQUEST, "MEMBER4014", "잘못된 이메일입니다."),

//JWT

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public enum SuccessStatus implements BaseCode {
MEMBER_DECLARE_DELETE(HttpStatus.OK, "MEMBER2008", "신고 삭제 성공했습니다."),
MEMBER_CONTACT_SUCCESS(HttpStatus.OK, "MEMBER2009", "연락가능 시간 변경 성공입니다."),


//POST
POST_FOLLOW_SUCCESS(HttpStatus.OK, "POST2001", "팔로우 성공입니다."),
POST_DELETE_FOLLOW_SUCCESS(HttpStatus.OK, "POST2002", "팔로우 취소 성공입니다."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public enum TokenType {

public TokenProvider(@Value("${jwt.token.secret}") String secretKey) {
this.secret = secretKey;
this.accessTokenValidityInMilliseconds = 1000 * 60 * 30L;
this.accessTokenValidityInMilliseconds = 1000 * 60 * 60* 6L;
}

@Override
Expand Down Expand Up @@ -82,7 +82,7 @@ public String createAccessToken(Long memberId, String memberRole, String email,

public String createRefreshToken(Collection<? extends GrantedAuthority> authorities) {
//2주
long tokenValidTime = 60 * 60 * 24 * 14 * 1000L;
long tokenValidTime = 60 * 60 * 24 * 30 * 1000L;
long now = (new Date()).getTime();
Date validity = new Date(now + tokenValidTime);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ public static MemberResponseDTO.LogoutResultDTO toLogoutResultDTO(Member member)
.build();
}

public static MemberResponseDTO.NewTokenDTO toNewTokenDTO(String accessToken, String refreshToken) {
public static MemberResponseDTO.NewTokenDTO toNewTokenDTO(String accessToken, LocalDateTime time) {
return MemberResponseDTO.NewTokenDTO.builder()
.refreshToken(refreshToken)
.accessExpireTime(time)
.accessToken(accessToken)
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@


import com.fasterxml.jackson.core.JsonProcessingException;
import com.umc.TheGoods.apiPayload.ApiResponse;
import com.umc.TheGoods.domain.member.Auth;
import com.umc.TheGoods.domain.member.Member;
import com.umc.TheGoods.domain.mypage.Account;
Expand All @@ -12,6 +13,8 @@
import com.umc.TheGoods.web.dto.member.MemberResponseDTO;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;


public interface MemberCommandService {

Expand All @@ -21,7 +24,7 @@ public interface MemberCommandService {

Member join(MemberRequestDTO.JoinDTO request);

MemberResponseDTO.LoginResultDTO login(MemberRequestDTO.LoginDTO request);
MemberResponseDTO.LoginResultDTO login(MemberRequestDTO.LoginDTO request, HttpServletResponse response);
void logout(String accessToken, Member member);
String regenerateAccessToken(RefreshToken refreshToken);

Expand All @@ -39,13 +42,13 @@ public interface MemberCommandService {

Boolean confirmEmailAuth(MemberRequestDTO.EmailAuthConfirmDTO request);

String emailAuthCreateJWT(MemberRequestDTO.EmailAuthConfirmDTO request);
MemberResponseDTO.LoginResultDTO emailAuthCreateJWT(MemberRequestDTO.EmailAuthConfirmDTO request, HttpServletResponse response);

Boolean updatePassword(MemberRequestDTO.PasswordUpdateDTO request, Member member);

String kakaoAuth(String code);
ApiResponse<?> kakaoAuth(String code, HttpServletResponse response);

String naverAuth(String code, String state);
ApiResponse<?> naverAuth(String code, String state, HttpServletResponse response);

Member profileModify(MultipartFile profile, String nickname, String introduce, Member member);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import antlr.Token;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.umc.TheGoods.apiPayload.ApiResponse;
import com.umc.TheGoods.apiPayload.code.status.ErrorStatus;
import com.umc.TheGoods.apiPayload.exception.handler.MemberHandler;
import com.umc.TheGoods.config.MailConfig;
Expand Down Expand Up @@ -44,6 +45,8 @@
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -159,7 +162,7 @@ public Member join(MemberRequestDTO.JoinDTO request) {
* @return
*/
@Override
public MemberResponseDTO.LoginResultDTO login(MemberRequestDTO.LoginDTO request) {
public MemberResponseDTO.LoginResultDTO login(MemberRequestDTO.LoginDTO request, HttpServletResponse response) {

//email 없음
Member selectedMember = memberRepository.findByEmail(request.getEmail())
Expand All @@ -173,10 +176,20 @@ public MemberResponseDTO.LoginResultDTO login(MemberRequestDTO.LoginDTO request)
throw new MemberHandler(ErrorStatus.MEMBER_PASSWORD_ERROR);
}

// refresh 생성후 쿠키로 만들고 response 헤더에 담기
RefreshToken refreshToken = redisService.generateRefreshToken(request.getEmail());
Cookie cookie = new Cookie("refreshToken",refreshToken.getToken());
cookie.setHttpOnly(true);
response.addCookie(cookie);

LocalDateTime currentDateTime = LocalDateTime.now();
LocalDateTime accessExpireTime = currentDateTime.plusHours(6);



return MemberResponseDTO.LoginResultDTO.builder()
.accessToken(redisService.saveLoginStatus(selectedMember.getId(), tokenProvider.createAccessToken(selectedMember.getId(), selectedMember.getMemberRole().toString() , request.getEmail(), Arrays.asList(new SimpleGrantedAuthority("USER")))))
.refreshToken(redisService.generateRefreshToken(request.getEmail()))
.accessExpireTime(accessExpireTime)
.build();

}
Expand Down Expand Up @@ -382,15 +395,29 @@ public Boolean confirmEmailAuth(MemberRequestDTO.EmailAuthConfirmDTO request) {
}

@Override
public String emailAuthCreateJWT(MemberRequestDTO.EmailAuthConfirmDTO request) {
public MemberResponseDTO.LoginResultDTO emailAuthCreateJWT(MemberRequestDTO.EmailAuthConfirmDTO request, HttpServletResponse response) {

Member member = memberRepository.findByEmail(request.getEmail())
.orElseThrow(() -> new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND));

List<String> roles = new ArrayList<>();
roles.add("ROLE_USER");

return tokenProvider.createAccessToken(member.getId(), member.getMemberRole().toString() , member.getEmail(), Arrays.asList(new SimpleGrantedAuthority("USER")));
// refresh 생성후 쿠키로 만들고 response 헤더에 담기
RefreshToken refreshToken = redisService.generateRefreshToken(request.getEmail());
Cookie cookie = new Cookie("refreshToken",refreshToken.getToken());
cookie.setHttpOnly(true);
response.addCookie(cookie);

LocalDateTime currentDateTime = LocalDateTime.now();
LocalDateTime accessExpireTime = currentDateTime.plusHours(6);

return MemberResponseDTO.LoginResultDTO.builder()
.accessToken(redisService.saveLoginStatus(member.getId(), tokenProvider.createAccessToken(member.getId(), member.getMemberRole().toString() , request.getEmail(), Arrays.asList(new SimpleGrantedAuthority("USER")))))
.accessExpireTime(accessExpireTime)
.build();


}

@Override
Expand All @@ -407,7 +434,7 @@ public Boolean updatePassword(MemberRequestDTO.PasswordUpdateDTO request, Member

@Override
@Transactional
public String kakaoAuth(String code) {
public ApiResponse<?> kakaoAuth(String code, HttpServletResponse res) {

String jwt;

Expand Down Expand Up @@ -486,21 +513,40 @@ public String kakaoAuth(String code) {

Optional<Member> member = memberRepository.findByPhone(phone);

LocalDateTime currentDateTime = LocalDateTime.now();
LocalDateTime accessExpireTime = currentDateTime.plusHours(6);



if (member.isPresent()) {

if(!this.checkDeregister(member.orElseThrow())){
throw new MemberHandler(ErrorStatus.MEMBER_INACTIVATE);
}
return tokenProvider.createAccessToken(member.get().getId(), member.get().getMemberRole().toString() , member.get().getEmail(), Arrays.asList(new SimpleGrantedAuthority("USER")));

// refresh 생성후 쿠키로 만들고 response 헤더에 담기
RefreshToken refreshToken = redisService.generateRefreshToken(member.get().getEmail());
Cookie cookie = new Cookie("refreshToken",refreshToken.getToken());
cookie.setHttpOnly(true);
res.addCookie(cookie);


return ApiResponse.onSuccess(MemberResponseDTO.LoginResultDTO.builder()
.accessToken(redisService.saveLoginStatus(member.get().getId(), tokenProvider.createAccessToken(member.get().getId(), member.get().getMemberRole().toString() , member.get().getEmail(), Arrays.asList(new SimpleGrantedAuthority("USER")))))
.accessExpireTime(accessExpireTime)
.build());

}

return phone + kakaoProfile.getKakao_account().email;
return ApiResponse.onFailure("MEMBER401", "로그인 실패 회원가입 필요", MemberConverter.toSocialJoinResultDTO(phone, kakaoProfile.getKakao_account().email));



}

@Override
@Transactional
public String naverAuth(String code, String state) {
public ApiResponse<?> naverAuth(String code, String state, HttpServletResponse res) {
RestTemplate rt = new RestTemplate();


Expand Down Expand Up @@ -571,17 +617,31 @@ public String naverAuth(String code, String state) {

Optional<Member> member = memberRepository.findByPhone(phone);

LocalDateTime currentDateTime = LocalDateTime.now();
LocalDateTime accessExpireTime = currentDateTime.plusHours(6);

if (member.isPresent()) {

if(!this.checkDeregister(member.orElseThrow())){
throw new MemberHandler(ErrorStatus.MEMBER_INACTIVATE);
}

return tokenProvider.createAccessToken(member.get().getId(), member.get().getMemberRole().toString() , member.get().getEmail(), Arrays.asList(new SimpleGrantedAuthority("USER")));
// refresh 생성후 쿠키로 만들고 response 헤더에 담기
RefreshToken refreshToken = redisService.generateRefreshToken(member.get().getEmail());
Cookie cookie = new Cookie("refreshToken",refreshToken.getToken());
cookie.setHttpOnly(true);
res.addCookie(cookie);

return ApiResponse.onSuccess(MemberResponseDTO.LoginResultDTO.builder()
.accessToken(redisService.saveLoginStatus(member.get().getId(), tokenProvider.createAccessToken(member.get().getId(), member.get().getMemberRole().toString() , member.get().getEmail(), Arrays.asList(new SimpleGrantedAuthority("USER")))))
.accessExpireTime(accessExpireTime)
.build());

}

return phone + naverProfile.getResponse().email;


return ApiResponse.onFailure("MEMBER401","로그인 실패 회원가입 필요",MemberConverter.toSocialJoinResultDTO(phone, naverProfile.getResponse().email));
}

@Override
Expand Down
50 changes: 25 additions & 25 deletions src/main/java/com/umc/TheGoods/web/controller/MemberController.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,11 @@
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -74,10 +77,10 @@ public ApiResponse<MemberResponseDTO.JoinResultDTO> join(@RequestBody @Valid Mem
//password
@PostMapping("/login")
@Operation(summary = "로그인 API", description = "request 파라미터 : 이메일, 비밀번호(String)")
public ApiResponse<MemberResponseDTO.LoginResultDTO> login(@RequestBody MemberRequestDTO.LoginDTO request) {
public ApiResponse<MemberResponseDTO.LoginResultDTO> login(@RequestBody MemberRequestDTO.LoginDTO request, HttpServletResponse response) {


return ApiResponse.onSuccess(memberCommandService.login(request));
return ApiResponse.onSuccess(memberCommandService.login(request,response));
}

@Operation(summary = "로그아웃 API", description = "로그아웃 API 입니다.")
Expand All @@ -92,10 +95,20 @@ public ApiResponse<MemberResponseDTO.LogoutResultDTO> logout(Authentication auth

@Operation(summary = "리프레쉬 토큰을 이용해 accessToken 재발급 API ️", description = "리프레쉬 토큰으로 accessToken 재발급하는 API입니다.")
@PostMapping("/token/regenerate")
public ApiResponse<MemberResponseDTO.NewTokenDTO> getNewToken(@RequestBody MemberRequestDTO.RefreshTokenDTO request) {
public ApiResponse<MemberResponseDTO.NewTokenDTO> getNewToken(@RequestBody MemberRequestDTO.RefreshTokenDTO request,
HttpServletResponse response) {
RefreshToken newRefreshToken = redisService.reGenerateRefreshToken(request);
String accessToken = memberCommandService.regenerateAccessToken(newRefreshToken);
return ApiResponse.onSuccess(MemberConverter.toNewTokenDTO(accessToken, newRefreshToken.getToken()));

LocalDateTime currentDateTime = LocalDateTime.now();
LocalDateTime accessExpireTime = currentDateTime.plusHours(6);

Cookie cookie = new Cookie("refreshToken", newRefreshToken.getToken());
cookie.setHttpOnly(true);

response.addCookie(cookie);

return ApiResponse.onSuccess(MemberConverter.toNewTokenDTO(accessToken,accessExpireTime));
}

@PostMapping("/jwt/test")
Expand Down Expand Up @@ -170,16 +183,16 @@ public ApiResponse<MemberResponseDTO.EmailAuthSendResultDTO> emailAuthSend(@Requ

@PostMapping("email/auth/verify")
@Operation(summary = "비밀번호 찾기에서 사용되는 email 인증 코드 검증 api", description = "request: 이메일, 코드 response: 인증완료 true")
public ApiResponse<MemberResponseDTO.EmailAuthConfirmResultDTO> emailAuth(@RequestBody MemberRequestDTO.EmailAuthConfirmDTO request) {
public ApiResponse<MemberResponseDTO.LoginResultDTO> emailAuth(@RequestBody MemberRequestDTO.EmailAuthConfirmDTO request, HttpServletResponse response) {
Boolean checkEmail = memberCommandService.confirmEmailAuth(request);


if (checkEmail == true) {
String jwt = memberCommandService.emailAuthCreateJWT(request);
return ApiResponse.onSuccess(MemberConverter.toEmailAuthConfirmResultDTO(checkEmail, jwt));

return ApiResponse.onSuccess(memberCommandService.emailAuthCreateJWT(request,response));
}

return ApiResponse.onSuccess(MemberConverter.toEmailAuthConfirmResultDTO(checkEmail, null));
return ApiResponse.onFailure(ErrorStatus.MEMBER_EMAIL_INCORRECT.getCode(),ErrorStatus.MEMBER_EMAIL_INCORRECT.getMessage(), null);

}

Expand All @@ -201,35 +214,22 @@ public ApiResponse<MemberResponseDTO.PasswordUpdateResultDTO> updatePassword(@Re

@GetMapping("/kakao/callback")
@Operation(summary = "카카오 소셜 로그인 api", description = "callback 용도 api여서 swagger에서 test 안됩니다")
public ApiResponse<?> kakaoCallback(@RequestParam String code) {
public ApiResponse<?> kakaoCallback(@RequestParam String code, HttpServletResponse response) {

String result = memberCommandService.kakaoAuth(code);
return memberCommandService.kakaoAuth(code, response);

//반환한 카카오 프로필에서 기존 회원이면 jwt 토큰 반환 아니면 회원가입 진행
//토큰 반환은 쉽지만 회원가입 로직으로 보내야하면 false 반환해서 회원가입 진행하도록하기

if (result.startsWith("010")) {
String phone = result.substring(0, 11);
String email = result.substring(11);
return ApiResponse.onFailure("로그인 실패", "회원가입 필요", MemberConverter.toSocialJoinResultDTO(phone, email));
}

return ApiResponse.onSuccess(MemberConverter.toSocialLoginResultDTO(result));
}

@GetMapping("/naver/callback")
@Operation(summary = "네이버 소셜 로그인 api", description = "callback 용도 api여서 swagger에서 test 안됩니다")
public ApiResponse<?> naverCallback(@RequestParam String code, String state) {
public ApiResponse<?> naverCallback(@RequestParam String code, String state, HttpServletResponse response) {

String result = memberCommandService.naverAuth(code, state);

if (result.startsWith("010")) {
String phone = result.substring(0, 11);
String email = result.substring(11);
return ApiResponse.onFailure("로그인 실패", "회원가입 필요", MemberConverter.toSocialJoinResultDTO(phone, email));
}
return memberCommandService.naverAuth(code, state, response);

return ApiResponse.onSuccess(MemberConverter.toSocialLoginResultDTO(result));
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ public static class JoinResultDTO {
@AllArgsConstructor
public static class LoginResultDTO {
String accessToken;
RefreshToken refreshToken;
LocalDateTime accessExpireTime;

}

@Builder
Expand Down Expand Up @@ -241,7 +242,7 @@ public static class AccountDTO {
@NoArgsConstructor
public static class NewTokenDTO{
private String accessToken;
private String refreshToken;
private LocalDateTime accessExpireTime;
}


Expand Down

0 comments on commit c77f16d

Please sign in to comment.