Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import io.f1.backend.domain.stat.entity.Stat;
import io.f1.backend.domain.user.dao.UserRepository;
import io.f1.backend.domain.user.dto.SessionUser;
import io.f1.backend.domain.user.dto.AuthenticationUser;
import io.f1.backend.domain.user.dto.UserPrincipal;
import io.f1.backend.domain.user.entity.User;

Expand Down Expand Up @@ -41,7 +41,7 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic
.map(this::updateLastLogin)
.orElseGet(() -> createNewUser(provider, providerId));

httpSession.setAttribute("OAuthUser", new SessionUser(user));
httpSession.setAttribute("OAuthUser", AuthenticationUser.from(user));
return new UserPrincipal(user, oAuth2User.getAttributes());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package io.f1.backend.domain.user.app;

import static io.f1.backend.domain.user.mapper.UserMapper.toSignupResponse;

import io.f1.backend.domain.user.dao.UserRepository;
import io.f1.backend.domain.user.dto.SessionUser;
import io.f1.backend.domain.user.dto.AuthenticationUser;
import io.f1.backend.domain.user.dto.SignupRequestDto;
import io.f1.backend.domain.user.dto.SignupResponseDto;
import io.f1.backend.domain.user.entity.User;
Expand All @@ -22,28 +24,29 @@ public class UserService {

@Transactional
public SignupResponseDto signup(HttpSession session, SignupRequestDto signupRequest) {
SessionUser sessionUser = extractSessionUser(session);
AuthenticationUser authenticationUser = extractSessionUser(session);

String nickname = signupRequest.nickname();
validateNickname(nickname);
validateDuplicateNickname(nickname);
validateNicknameFormat(nickname);
validateNicknameDuplicate(nickname);

User user = updateUserNickname(sessionUser.getUserId(), nickname);
User user = updateUserNickname(authenticationUser.userId(), nickname);
updateSessionAfterSignup(session, user);
SecurityUtils.setAuthentication(user);

return SignupResponseDto.toDto(user);
return toSignupResponse(user);
}

private SessionUser extractSessionUser(HttpSession session) {
SessionUser sessionUser = (SessionUser) session.getAttribute("OAuthUser");
if (sessionUser == null) {
throw new RuntimeException("세션에 OAuth 정보 없음");
private AuthenticationUser extractSessionUser(HttpSession session) {
AuthenticationUser authenticationUser =
(AuthenticationUser) session.getAttribute("OAuthUser");
if (authenticationUser == null) {
throw new RuntimeException("E401001: 로그인이 필요합니다.");
}
return sessionUser;
return authenticationUser;
}

private void validateNickname(String nickname) {
private void validateNicknameFormat(String nickname) {
if (nickname == null || nickname.trim().isEmpty()) {
throw new RuntimeException("E400002: 닉네임은 필수 입력입니다.");
}
Expand All @@ -55,22 +58,26 @@ private void validateNickname(String nickname) {
}
}

private void validateDuplicateNickname(String nickname) {
@Transactional(readOnly = true)
public void validateNicknameDuplicate(String nickname) {
if (userRepository.existsUserByNickname(nickname)) {
throw new RuntimeException("닉네임 중복");
throw new RuntimeException("E409001: 중복된 닉네임입니다.");
}
}

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

return userRepository.save(user);
}

private void updateSessionAfterSignup(HttpSession session, User user) {
session.removeAttribute("OAuthUser");
session.setAttribute("user", new SessionUser(user));
session.setAttribute("user", AuthenticationUser.from(user));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.f1.backend.domain.user.dto;

import io.f1.backend.domain.user.entity.User;

import java.io.Serializable;

public record AuthenticationUser(Long userId, String nickname, String providerId)
implements Serializable {

public static AuthenticationUser from(User user) {
return new AuthenticationUser(user.getId(), user.getNickname(), user.getProviderId());
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,22 +1,3 @@
package io.f1.backend.domain.user.dto;

import io.f1.backend.domain.user.entity.User;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SignupResponseDto {

private Long id;
private String nickname;

public static SignupResponseDto toDto(User user) {
return SignupResponseDto.builder().id(user.getId()).nickname(user.getNickname()).build();
}
}
public record SignupResponseDto(Long id, String nickname) {}
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@
public class UserPrincipal implements UserDetails, OAuth2User {

public static final String ROLE_USER = "ROLE_USER";
private final User user;
private final AuthenticationUser authenticationUser;
private final Map<String, Object> attributes;

public UserPrincipal(User user, Map<String, Object> attributes) {
this.user = user;
this.authenticationUser = AuthenticationUser.from(user);
this.attributes = attributes;
}

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

public Long getUserId() {
return user.getId();
return authenticationUser.userId();
}

public String getUserNickname() {
return user.getNickname();
return authenticationUser.nickname();
}

@Override
public String getName() {
return user.getProviderId();
return authenticationUser.providerId();
}

@Override
Expand All @@ -54,7 +54,7 @@ public String getPassword() {

@Override
public String getUsername() {
return user.getProviderId();
return authenticationUser.providerId();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.f1.backend.domain.user.mapper;

import io.f1.backend.domain.user.dto.SignupResponseDto;
import io.f1.backend.domain.user.entity.User;

public class UserMapper {

private UserMapper() {}

public static SignupResponseDto toSignupResponse(User user) {
return new SignupResponseDto(user.getId(), user.getNickname());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ public SecurityFilterChain userFilterChain(HttpSecurity http) throws Exception {
.logoutSuccessHandler(oAuthLogoutSuccessHandler)
.clearAuthentication(true)
.invalidateHttpSession(true)
.permitAll());
.permitAll())
.sessionManagement(
session -> session.sessionFixation().migrateSession().maximumSessions(1));
return http.build();
}
}
18 changes: 18 additions & 0 deletions backend/src/main/java/io/f1/backend/global/util/SecurityUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import io.f1.backend.domain.user.entity.User;

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

import java.util.Collections;
Expand All @@ -19,4 +20,21 @@ public static void setAuthentication(User user) {
userPrincipal, null, userPrincipal.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authentication);
}

public static UserPrincipal getCurrentUserPrincipal() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null
&& authentication.getPrincipal() instanceof UserPrincipal userPrincipal) {
return userPrincipal;
}
throw new RuntimeException("E401001: 로그인이 필요합니다.");
}

public static Long getCurrentUserId() {
return getCurrentUserPrincipal().getUserId();
}

public static String getCurrentUserNickname() {
return getCurrentUserPrincipal().getUserNickname();
}
}
Loading