Skip to content

Commit 3699062

Browse files
authored
♻️ [refactor] Kakao OAuth 기능 리팩토링 (#28)
* ♻️ refactor: UserMapper에 toSignupResponse() 추가 * ♻️ refactor: 예외 메시지 수정, @transactional 명시 * ♻️ refactor: UserPrincipal 필드 수정(User -> AuthenticationUser) * ♻️ refactor: 사용자 인증 정보를 반환하는 util 메서드 추가 * 🔧 chore: 세션 정책 설정 * chore: Java 스타일 수정 * ♻️ refactor: 매직 스트링 제거 * chore: Java 스타일 수정 --------- Co-authored-by: github-actions <>
1 parent d4a0079 commit 3699062

File tree

10 files changed

+94
-71
lines changed

10 files changed

+94
-71
lines changed

backend/src/main/java/io/f1/backend/domain/user/app/CustomOAuthUserService.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package io.f1.backend.domain.user.app;
22

3+
import static io.f1.backend.domain.user.constants.SessionKeys.*;
4+
35
import io.f1.backend.domain.stat.entity.Stat;
46
import io.f1.backend.domain.user.dao.UserRepository;
5-
import io.f1.backend.domain.user.dto.SessionUser;
7+
import io.f1.backend.domain.user.dto.AuthenticationUser;
68
import io.f1.backend.domain.user.dto.UserPrincipal;
79
import io.f1.backend.domain.user.entity.User;
810

@@ -41,7 +43,7 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic
4143
.map(this::updateLastLogin)
4244
.orElseGet(() -> createNewUser(provider, providerId));
4345

44-
httpSession.setAttribute("OAuthUser", new SessionUser(user));
46+
httpSession.setAttribute(OAUTH_USER, AuthenticationUser.from(user));
4547
return new UserPrincipal(user, oAuth2User.getAttributes());
4648
}
4749

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package io.f1.backend.domain.user.app;
22

3+
import static io.f1.backend.domain.user.constants.SessionKeys.OAUTH_USER;
4+
import static io.f1.backend.domain.user.constants.SessionKeys.USER;
5+
import static io.f1.backend.domain.user.mapper.UserMapper.toSignupResponse;
6+
37
import io.f1.backend.domain.user.dao.UserRepository;
4-
import io.f1.backend.domain.user.dto.SessionUser;
8+
import io.f1.backend.domain.user.dto.AuthenticationUser;
59
import io.f1.backend.domain.user.dto.SignupRequestDto;
610
import io.f1.backend.domain.user.dto.SignupResponseDto;
711
import io.f1.backend.domain.user.entity.User;
@@ -22,28 +26,29 @@ public class UserService {
2226

2327
@Transactional
2428
public SignupResponseDto signup(HttpSession session, SignupRequestDto signupRequest) {
25-
SessionUser sessionUser = extractSessionUser(session);
29+
AuthenticationUser authenticationUser = extractSessionUser(session);
2630

2731
String nickname = signupRequest.nickname();
28-
validateNickname(nickname);
29-
validateDuplicateNickname(nickname);
32+
validateNicknameFormat(nickname);
33+
validateNicknameDuplicate(nickname);
3034

31-
User user = updateUserNickname(sessionUser.getUserId(), nickname);
35+
User user = updateUserNickname(authenticationUser.userId(), nickname);
3236
updateSessionAfterSignup(session, user);
3337
SecurityUtils.setAuthentication(user);
3438

35-
return SignupResponseDto.toDto(user);
39+
return toSignupResponse(user);
3640
}
3741

38-
private SessionUser extractSessionUser(HttpSession session) {
39-
SessionUser sessionUser = (SessionUser) session.getAttribute("OAuthUser");
40-
if (sessionUser == null) {
41-
throw new RuntimeException("세션에 OAuth 정보 없음");
42+
private AuthenticationUser extractSessionUser(HttpSession session) {
43+
AuthenticationUser authenticationUser =
44+
(AuthenticationUser) session.getAttribute(OAUTH_USER);
45+
if (authenticationUser == null) {
46+
throw new RuntimeException("E401001: 로그인이 필요합니다.");
4247
}
43-
return sessionUser;
48+
return authenticationUser;
4449
}
4550

46-
private void validateNickname(String nickname) {
51+
private void validateNicknameFormat(String nickname) {
4752
if (nickname == null || nickname.trim().isEmpty()) {
4853
throw new RuntimeException("E400002: 닉네임은 필수 입력입니다.");
4954
}
@@ -55,22 +60,26 @@ private void validateNickname(String nickname) {
5560
}
5661
}
5762

58-
private void validateDuplicateNickname(String nickname) {
63+
@Transactional(readOnly = true)
64+
public void validateNicknameDuplicate(String nickname) {
5965
if (userRepository.existsUserByNickname(nickname)) {
60-
throw new RuntimeException("닉네임 중복");
66+
throw new RuntimeException("E409001: 중복된 닉네임입니다.");
6167
}
6268
}
6369

64-
private User updateUserNickname(Long userId, String nickname) {
70+
@Transactional
71+
public User updateUserNickname(Long userId, String nickname) {
6572
User user =
66-
userRepository.findById(userId).orElseThrow(() -> new RuntimeException("사용자 없음"));
73+
userRepository
74+
.findById(userId)
75+
.orElseThrow(() -> new RuntimeException("E404001: 존재하지 않는 회원입니다."));
6776
user.updateNickname(nickname);
6877

6978
return userRepository.save(user);
7079
}
7180

7281
private void updateSessionAfterSignup(HttpSession session, User user) {
73-
session.removeAttribute("OAuthUser");
74-
session.setAttribute("user", new SessionUser(user));
82+
session.removeAttribute(OAUTH_USER);
83+
session.setAttribute(USER, AuthenticationUser.from(user));
7584
}
7685
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package io.f1.backend.domain.user.constants;
2+
3+
public final class SessionKeys {
4+
5+
private SessionKeys() {}
6+
7+
public static final String OAUTH_USER = "OAuthUser";
8+
public static final String USER = "user";
9+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.f1.backend.domain.user.dto;
2+
3+
import io.f1.backend.domain.user.entity.User;
4+
5+
import java.io.Serializable;
6+
7+
public record AuthenticationUser(Long userId, String nickname, String providerId)
8+
implements Serializable {
9+
10+
public static AuthenticationUser from(User user) {
11+
return new AuthenticationUser(user.getId(), user.getNickname(), user.getProviderId());
12+
}
13+
}

backend/src/main/java/io/f1/backend/domain/user/dto/SessionUser.java

Lines changed: 0 additions & 24 deletions
This file was deleted.
Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,3 @@
11
package io.f1.backend.domain.user.dto;
22

3-
import io.f1.backend.domain.user.entity.User;
4-
5-
import lombok.AllArgsConstructor;
6-
import lombok.Builder;
7-
import lombok.Getter;
8-
import lombok.NoArgsConstructor;
9-
10-
@Getter
11-
@Builder
12-
@NoArgsConstructor
13-
@AllArgsConstructor
14-
public class SignupResponseDto {
15-
16-
private Long id;
17-
private String nickname;
18-
19-
public static SignupResponseDto toDto(User user) {
20-
return SignupResponseDto.builder().id(user.getId()).nickname(user.getNickname()).build();
21-
}
22-
}
3+
public record SignupResponseDto(Long id, String nickname) {}

backend/src/main/java/io/f1/backend/domain/user/dto/UserPrincipal.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@
1616
public class UserPrincipal implements UserDetails, OAuth2User {
1717

1818
public static final String ROLE_USER = "ROLE_USER";
19-
private final User user;
19+
private final AuthenticationUser authenticationUser;
2020
private final Map<String, Object> attributes;
2121

2222
public UserPrincipal(User user, Map<String, Object> attributes) {
23-
this.user = user;
23+
this.authenticationUser = AuthenticationUser.from(user);
2424
this.attributes = attributes;
2525
}
2626

@@ -30,16 +30,16 @@ public Map<String, Object> getAttributes() {
3030
}
3131

3232
public Long getUserId() {
33-
return user.getId();
33+
return authenticationUser.userId();
3434
}
3535

3636
public String getUserNickname() {
37-
return user.getNickname();
37+
return authenticationUser.nickname();
3838
}
3939

4040
@Override
4141
public String getName() {
42-
return user.getProviderId();
42+
return authenticationUser.providerId();
4343
}
4444

4545
@Override
@@ -54,7 +54,7 @@ public String getPassword() {
5454

5555
@Override
5656
public String getUsername() {
57-
return user.getProviderId();
57+
return authenticationUser.providerId();
5858
}
5959

6060
@Override
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.f1.backend.domain.user.mapper;
2+
3+
import io.f1.backend.domain.user.dto.SignupResponseDto;
4+
import io.f1.backend.domain.user.entity.User;
5+
6+
public class UserMapper {
7+
8+
private UserMapper() {}
9+
10+
public static SignupResponseDto toSignupResponse(User user) {
11+
return new SignupResponseDto(user.getId(), user.getNickname());
12+
}
13+
}

backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ public SecurityFilterChain userFilterChain(HttpSecurity http) throws Exception {
5858
.logoutSuccessHandler(oAuthLogoutSuccessHandler)
5959
.clearAuthentication(true)
6060
.invalidateHttpSession(true)
61-
.permitAll());
61+
.permitAll())
62+
.sessionManagement(
63+
session -> session.sessionFixation().migrateSession().maximumSessions(1));
6264
return http.build();
6365
}
6466
}

backend/src/main/java/io/f1/backend/global/util/SecurityUtils.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import io.f1.backend.domain.user.entity.User;
55

66
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
7+
import org.springframework.security.core.Authentication;
78
import org.springframework.security.core.context.SecurityContextHolder;
89

910
import java.util.Collections;
@@ -19,4 +20,21 @@ public static void setAuthentication(User user) {
1920
userPrincipal, null, userPrincipal.getAuthorities());
2021
SecurityContextHolder.getContext().setAuthentication(authentication);
2122
}
23+
24+
public static UserPrincipal getCurrentUserPrincipal() {
25+
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
26+
if (authentication != null
27+
&& authentication.getPrincipal() instanceof UserPrincipal userPrincipal) {
28+
return userPrincipal;
29+
}
30+
throw new RuntimeException("E401001: 로그인이 필요합니다.");
31+
}
32+
33+
public static Long getCurrentUserId() {
34+
return getCurrentUserPrincipal().getUserId();
35+
}
36+
37+
public static String getCurrentUserNickname() {
38+
return getCurrentUserPrincipal().getUserNickname();
39+
}
2240
}

0 commit comments

Comments
 (0)