Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

토큰 값에 memberId 추가 및 기타 예외 처리 #219

Merged
merged 10 commits into from
Mar 19, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public class SecurityConfig {
private static final String[] PUBLIC_POST = {
"/members/join", "/members/login",
"/email/request", "/email/verify",
"/posts/{postId}/vote"
"/posts/{postId}/vote", "/files/image/upload"
};

private static final String[] PUBLIC_PUT = {
Expand Down
24 changes: 17 additions & 7 deletions src/main/java/balancetalk/global/jwt/JwtTokenProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,11 @@ public class JwtTokenProvider {
/**
* Access 토큰 생성
*/
public String createAccessToken(Authentication authentication) {
public String createAccessToken(Authentication authentication, Long memberId) {
validateAuthentication(authentication);
Claims claims = Jwts.claims().setSubject(authentication.getName());
Claims claims = Jwts.claims();
claims.put("memberId", memberId);
claims.setSubject(authentication.getName());
Date now = new Date();
Date expireDate = new Date(now.getTime() + accessExpirationTime);

Expand All @@ -56,9 +58,11 @@ public String createAccessToken(Authentication authentication) {
/**
* Refresh 토큰 생성
*/
public String createRefreshToken(Authentication authentication) {
public String createRefreshToken(Authentication authentication, Long memberId) {
validateAuthentication(authentication);
Claims claims = Jwts.claims().setSubject(authentication.getName());
Claims claims = Jwts.claims();
claims.put("memberId", memberId);
claims.setSubject(authentication.getName());
Date now = new Date();
Date expireDate = new Date(now.getTime() + refreshExpirationTime);

Expand Down Expand Up @@ -94,6 +98,12 @@ public String getPayload(String token) {
return Jwts.parserBuilder().setSigningKey(secretKey).build().parseClaimsJws(token).getBody().getSubject();
}

public Long getMemberId(String token) {
validateToken(token);
Claims claims = Jwts.parserBuilder().setSigningKey(secretKey).build().parseClaimsJws(token).getBody();
return claims.get("memberId", Long.class);
}

public boolean validateToken(String token) {
try {
Jws<Claims> claims = Jwts.parserBuilder().setSigningKey(secretKey).build().parseClaimsJws(token);
Expand All @@ -113,7 +123,7 @@ private void validateAuthentication(Authentication authentication) {
}
}

public TokenDto reissueToken(String refreshToken) {
public TokenDto reissueToken(String refreshToken, Long memberId) {
validateToken(refreshToken);
Authentication authentication = getAuthentication(refreshToken);
// redis에 저장된 RefreshToken 값을 가져옴
Expand All @@ -122,8 +132,8 @@ public TokenDto reissueToken(String refreshToken) {
throw new BalanceTalkException(ErrorCode.INVALID_REFRESH_TOKEN);
}
TokenDto tokenDto = new TokenDto(
createAccessToken(authentication),
createRefreshToken(authentication)
createAccessToken(authentication, memberId),
createRefreshToken(authentication, memberId)
);
return tokenDto;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import balancetalk.module.member.domain.Member;
import balancetalk.module.member.domain.MemberRepository;
import balancetalk.module.member.dto.*;
import io.jsonwebtoken.ExpiredJwtException;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -24,7 +25,7 @@
import java.util.List;
import java.util.stream.Collectors;

import static balancetalk.global.exception.ErrorCode.NOT_FOUND_FILE;
import static balancetalk.global.exception.ErrorCode.*;

@Slf4j
@Service
Expand All @@ -40,6 +41,12 @@ public class MemberService {

@Transactional
public Long join(final JoinRequest joinRequest) {
if (memberRepository.existsByEmail(joinRequest.getEmail())) {
throw new BalanceTalkException(ALREADY_REGISTERED_EMAIL);
}
if (memberRepository.existsByNickname(joinRequest.getNickname())) {
throw new BalanceTalkException(ALREADY_REGISTERED_NICKNAME);
}
joinRequest.setPassword(passwordEncoder.encode(joinRequest.getPassword()));
File profilePhoto = null;
if (joinRequest.getProfilePhoto() != null && !joinRequest.getProfilePhoto().isEmpty()) {
Expand All @@ -63,8 +70,8 @@ public TokenDto login(final LoginRequest loginRequest) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequest.getEmail(), loginRequest.getPassword())
);
String refreshToken = jwtTokenProvider.createRefreshToken(authentication);
return jwtTokenProvider.reissueToken(refreshToken); // 만료되었다면, 재발급
String refreshToken = jwtTokenProvider.createRefreshToken(authentication, member.getId());
return jwtTokenProvider.reissueToken(refreshToken, member.getId()); // 만료되었다면, 재발급
}

@Transactional(readOnly = true)
Expand Down Expand Up @@ -116,6 +123,9 @@ public void delete(final LoginRequest loginRequest, HttpServletRequest request)
@Transactional
public void logout(){
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
throw new BalanceTalkException(ErrorCode.AUTHENTICATION_REQUIRED);
}
String username = authentication.getName();
redisService.deleteValues(username);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
Expand Down Expand Up @@ -87,6 +88,14 @@ void setUp() {
.password(joinRequest.getPassword())
.nickname("멤버1")
.build();

// SecurityContext에 인증된 사용자 설정
Authentication authentication = mock(Authentication.class);
SecurityContext securityContext = mock(SecurityContext.class);
lenient().when(securityContext.getAuthentication()).thenReturn(authentication);
SecurityContextHolder.setContext(securityContext);

lenient().when(authentication.getName()).thenReturn(member.getEmail());
}

@AfterEach
Expand Down Expand Up @@ -121,7 +130,7 @@ void LoginMember_Success() {
// given
when(memberRepository.findByEmail(loginRequest.getEmail())).thenReturn(Optional.ofNullable(member));
when(passwordEncoder.matches(eq(loginRequest.getPassword()), eq(joinRequest.getPassword()))).thenReturn(true);
when(jwtTokenProvider.reissueToken(any())).thenReturn(new TokenDto(accessToken, refreshToken));
when(jwtTokenProvider.reissueToken(any() , anyLong())).thenReturn(new TokenDto(accessToken, refreshToken));

// when
TokenDto result = memberService.login(loginRequest);
Expand Down Expand Up @@ -314,12 +323,8 @@ void deleteMemberFailure_PasswordMismatch() {
@Test
@DisplayName("로그아웃 - 성공")
void logoutMemberSuccess() {
// given, 로그인 상태
when(userDetails.getUsername()).thenReturn(member.getEmail());
when(authentication.getPrincipal()).thenReturn(userDetails);
SecurityContextHolder.getContext().setAuthentication(authentication);

when(redisService.getValues(member.getEmail())).thenReturn(refreshToken);
// given,
lenient().when(redisService.getValues(member.getEmail())).thenReturn(refreshToken);

// when
memberService.logout();
Expand All @@ -331,12 +336,8 @@ void logoutMemberSuccess() {
@Test
@DisplayName("로그아웃 실패 - redis에 저장된 정보가 없음")
void logoutFailure_RedisNull(){
// given, 로그인 상태
when(userDetails.getUsername()).thenReturn(member.getEmail());
when(authentication.getPrincipal()).thenReturn(userDetails);
SecurityContextHolder.getContext().setAuthentication(authentication);

when(redisService.getValues(anyString())).thenReturn(null);
// given
when(SecurityContextHolder.getContext().getAuthentication()).thenReturn(null);

// when & then
assertThatThrownBy(() -> memberService.logout())
Expand Down
Loading