Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
1739b8a
refactor: 불필요한 패키지 제거
m-a-king Dec 29, 2024
0aa1bec
refactor: 패키지 이동
m-a-king Dec 29, 2024
adb632a
refactor: 네이버 oauth 정보 범위 축소
m-a-king Dec 29, 2024
97b6f04
refactor: 패키지 이동
m-a-king Dec 29, 2024
be3f7ac
refactor: 주석 제거
m-a-king Dec 29, 2024
0f505a7
feat(jwt): 접두사 포함 getter 추가
m-a-king Dec 30, 2024
6afd89a
feat(oauth): oauth 정보 도메인(엔티티) 추가
m-a-king Dec 30, 2024
d5ad386
feat(oauth): oauth 정보 존재 확인 추가
m-a-king Dec 30, 2024
294ab05
feat(oauth): oauth 정보 등록 추가
m-a-king Dec 30, 2024
db19228
feat(oauth): oauth 정보 리포지토리 추가
m-a-king Dec 30, 2024
a912c1a
feat(oauth): oauth 정보 변환 기능 추가
m-a-king Dec 30, 2024
6856655
feat(registerUser): oauth, local 유저 등록 기능 추가
m-a-king Dec 30, 2024
156087e
feat(user): 유저 도메인 추가
m-a-king Dec 30, 2024
1915133
feat(user): 유저 공통 속성 도메인 추가
m-a-king Dec 30, 2024
927146f
feat(user): 유저 설정 도메인 추가
m-a-king Dec 30, 2024
3a85947
feat(user): 유저 설정 리포지토리 추가
m-a-king Dec 30, 2024
2322782
feat(user): 유저 리포지토리 추가
m-a-king Dec 30, 2024
3c7d762
feat(user): 유저 공통 속성 리포지토리 추가
m-a-king Dec 30, 2024
7b93cdc
feat(auth): 유저 인증 정보 추가
m-a-king Dec 30, 2024
987054d
feat(oauth): 유저 불러오기 기능 수정
m-a-king Dec 30, 2024
4c38f74
feat(oauth): 인증 성공 핸들러 수정
m-a-king Dec 30, 2024
bf7fa78
refactor: 패키지 이동
m-a-king Dec 30, 2024
4d54d78
feat(userRole): default oauth userRole getter 추가
m-a-king Dec 30, 2024
539b5d8
refactor(oauth): 로그인 리디렉션 개선
m-a-king Dec 31, 2024
144fa4e
feat(user): 유저 예외 추가
m-a-king Dec 31, 2024
5c7172a
feat(user): 유저 공통 속성 필드 추가
m-a-king Dec 31, 2024
fb100d6
feat(redirection): 로그인 리디렉션 수정
m-a-king Dec 31, 2024
1cb8249
feat(user): 유저 리포지토리 조회 기능 추가
m-a-king Dec 31, 2024
5d73734
feat(oauth): oauth 정보 조회 서비스 추가
m-a-king Dec 31, 2024
6e2d1a3
feat(oauth): oauth 정보 처리 추가
m-a-king Dec 31, 2024
73a1d13
feat(user): 유저 공통 속성 리포지토리 조회 기능 추가
m-a-king Dec 31, 2024
9d38623
feat(user): 유저 공통 속성 베이스 엔티티 상속
m-a-king Dec 31, 2024
239bf32
feat(user): 유저 공통 속성 리포지토리 수정 및 기능 추가
m-a-king Dec 31, 2024
89bb67a
feat(user): 유저 조회 기능 추가
m-a-king Dec 31, 2024
1df63ce
feat(user): 기본 정보 사용자화 검증 기능 추가
m-a-king Dec 31, 2024
654926c
feat(oauth): 네이버 관련 oauth 로직 삭제
m-a-king Dec 31, 2024
7750e80
refactor(user): 유저 인증 정보 dto 네이밍 변경
m-a-king Dec 31, 2024
9a02fed
feat(oauth): oauth 정보 클래스의 baseEntity 상속
m-a-king Dec 31, 2024
d89e00f
feat(oauth): oauthInfo 확인 의존성 수정, 메서드 네이밍 수정
m-a-king Dec 31, 2024
e480db5
feat(oauth): OAuthInfo 리포지토리 구현체 개선
m-a-king Dec 31, 2024
c9774f0
refactor(user): 유저 리포지토리 개선
m-a-king Jan 1, 2025
a1a6db0
refactor(user): userAuthInfo 네이밍 변경
m-a-king Jan 1, 2025
5be3fd2
refactor(user): user entity 네이밍 변경
m-a-king Jan 1, 2025
0f4b57b
fix(user): 유저 공통 속성 리포지토리 문제 해결
m-a-king Jan 1, 2025
0f3c0d2
feat(user): 유저 공통 속성 사용자화 업데이트 기능 추가
m-a-king Jan 1, 2025
5844504
fix(user): 유저 리포지토리 문제 해결
m-a-king Jan 1, 2025
3936b5f
feat(user): 유저 쿼리 서비스 기능 추가
m-a-king Jan 1, 2025
36c5a1b
test(user): 유저 조회 테스트 추가
m-a-king Jan 1, 2025
bf2bc3e
feat(user): 유저 세팅의 baseEntity 상속
m-a-king Jan 1, 2025
3936954
feat(user): 유저 세팅 조회 기능 추가
m-a-king Jan 1, 2025
af2fbdf
test(user): 유저 세팅 조회, 저장 테스트 추가
m-a-king Jan 1, 2025
80eba66
test(user): 유저 조회 테스트 추가
m-a-king Jan 1, 2025
7eaa28c
test(user): 유저 공통 속성 저장 테스트 추가
m-a-king Jan 1, 2025
cfef5cb
test(user): 유저 공통 속성 사용자화 검증 테스트 추가
m-a-king Jan 1, 2025
f568e01
test(user): 유저 등록 테스트 추가
m-a-king Jan 1, 2025
71dc6a4
refactor: 깃허브 개행 문제 해결
m-a-king Jan 1, 2025
12186c5
refactor: 깃허브 개행 문제 해결
m-a-king Jan 2, 2025
0a44b9a
fix(oauth): 트랜잭션 수정
m-a-king Jan 2, 2025
1c3024c
test(user): 객체간 동등 비교 추가
m-a-king Jan 2, 2025
b0b3490
feat(oauth): 정적 팩토리 메서드 추가
m-a-king Jan 2, 2025
f25b048
test(refactor): 테스트 리팩토링
m-a-king Jan 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.somemore.domains.volunteer.domain;

import com.somemore.global.auth.oauth.OAuthProvider;
import com.somemore.global.auth.oauth.domain.OAuthProvider;
import com.somemore.global.common.entity.BaseEntity;
import com.somemore.domains.volunteer.dto.request.VolunteerProfileUpdateRequestDto;
import jakarta.persistence.*;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.somemore.domains.volunteer.dto.request;

import com.somemore.global.auth.oauth.OAuthProvider;
import com.somemore.global.auth.oauth.domain.OAuthProvider;

public record VolunteerRegisterRequestDto(
OAuthProvider oAuthProvider,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public void deleteAccessToken(HttpServletResponse response) {
}

private static ResponseCookie generateCookie(TokenType tokenType, String value) {
return ResponseCookie.from(TokenType.ACCESS.name(), value) // 덮어쓰기 위해서 고정 값
return ResponseCookie.from(TokenType.ACCESS.name(), value)
.domain(".somemore.site")
.httpOnly(true)
.secure(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.somemore.global.auth.cookie.CookieUseCase;
import com.somemore.global.auth.jwt.domain.EncodedToken;
import com.somemore.global.auth.jwt.domain.UserRole;
import com.somemore.user.domain.UserRole;
import com.somemore.global.auth.jwt.usecase.GenerateTokensOnLoginUseCase;
import jakarta.servlet.FilterChain;
import jakarta.servlet.http.HttpServletRequest;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import com.somemore.global.auth.authentication.JwtAuthenticationToken;
import com.somemore.global.auth.jwt.domain.EncodedToken;
import com.somemore.global.auth.jwt.domain.TokenType;
import com.somemore.global.auth.jwt.domain.UserRole;
import com.somemore.user.domain.UserRole;
import com.somemore.global.auth.jwt.usecase.JwtUseCase;
import com.somemore.domains.center.usecase.query.CenterSignUseCase;
import lombok.RequiredArgsConstructor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
public record EncodedToken(String value) {

private static final String UNINITIALIZED = "UNINITIALIZED";
private static final String PREFIX = "Bearer ";

public String getValueWithPrefix() {
return PREFIX + this.value;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

매번 상수를 깔끔하게 사용하시는것 같아요 좋습니다

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니다 ㅎㅎ

}

public boolean isUninitialized() {
return value == null
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.somemore.global.auth.jwt.service;

import com.somemore.global.auth.jwt.domain.UserRole;
import com.somemore.user.domain.UserRole;
import com.somemore.global.auth.jwt.domain.EncodedToken;
import com.somemore.global.auth.jwt.domain.TokenType;
import com.somemore.global.auth.jwt.generator.JwtGenerator;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.somemore.global.auth.jwt.usecase;

import com.somemore.global.auth.jwt.domain.EncodedToken;
import com.somemore.global.auth.jwt.domain.UserRole;
import com.somemore.user.domain.UserRole;

import java.util.UUID;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.somemore.global.auth.oauth.checker;

import com.somemore.global.auth.oauth.domain.OAuthProvider;

public interface OAuthInfoChecker {
boolean doesUserExist(OAuthProvider provider, String id);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.somemore.global.auth.oauth.checker;

import com.somemore.global.auth.oauth.domain.OAuthProvider;
import com.somemore.global.auth.oauth.repository.OAuthInfoRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class OAuthInfoCheckerImpl implements OAuthInfoChecker {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cheker가 보편적인 이름인가요? 나중에 참고해보려고 여쭤봅니다!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

존재 여부를 확인하는 유즈케이스에서 클래스 이름에 exist라는 단어를 사용하는 대신, 더 추상화된 이름을 선택하려고 고민했습니다. 클래스는 추상적인 이름을, 메서드는 구체화된 이름을 갖도록 설계하는 것을 목표로 했습니다.

또한, validate는 검증의 뉘앙스가 강하고, inspector나 analyzer는 작업의 성격과 잘 맞지 않아 적합하지 않다고 판단했습니다. 만약 검증의 의미가 더 강했다면 validate를, 추가적인 처리가 필요했다면 processor를 사용했겠지만, 이번 작업은 단순히 존재 여부만을 확인하는 가벼운 작업이기 때문에, exist라는 단어를 피하면서도 적합한 이름으로 checker를 선택했습니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

덧붙여, 원래 기존 도메인에서는 이러한 로직이 쿼리 유즈케이스(서비스)에 포함되는 것이 일반적이지만, 인증/인가 로직에서는 별도로 구분하는 것이 훨씬 명확하고 적합하다고 판단해서 checker와 같은 클래스가 나타난 것 같습니다.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

답변 감사합니다!


private final OAuthInfoRepository oAuthInfoRepository;

@Override
public boolean doesUserExist(OAuthProvider provider, String id) {
return oAuthInfoRepository.existsByOAuthProviderAndOauthId(provider, id);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.somemore.global.auth.oauth.converter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.somemore.global.auth.oauth.domain.CommonOAuthInfo;
import com.somemore.global.auth.oauth.domain.OAuthProvider;
import com.somemore.global.auth.oauth.naver.dto.NaverUserProfileResponseDto;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Component;

@Component
public class NaverOAuthResponseConverter implements OAuthResponseConverter {

@Override
public CommonOAuthInfo convert(OAuth2User oAuth2User) {
NaverUserProfileResponseDto naverUserProfileResponseDto = new ObjectMapper().convertValue(oAuth2User.getAttributes(), NaverUserProfileResponseDto.class);

return new CommonOAuthInfo(
OAuthProvider.NAVER,
naverUserProfileResponseDto.response().id());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.somemore.global.auth.oauth.converter;

import com.somemore.global.auth.oauth.domain.CommonOAuthInfo;
import org.springframework.security.oauth2.core.user.OAuth2User;

public interface OAuthResponseConverter {
CommonOAuthInfo convert(OAuth2User oAuth2User);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.somemore.global.auth.oauth.domain;

public record CommonOAuthInfo(
OAuthProvider provider,
String oauthId) {
}
55 changes: 55 additions & 0 deletions src/main/java/com/somemore/global/auth/oauth/domain/OAuthInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.somemore.global.auth.oauth.domain;

import com.somemore.global.common.entity.BaseEntity;
import com.somemore.user.domain.User;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.UUID;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@Table(name = "oauth_info")
public class OAuthInfo extends BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Long id;

@Column(name = "user_id", nullable = false)
private UUID userId;

@Column(name = "oauth_id", nullable = false)
private String oauthId;

@Enumerated(EnumType.STRING)
@Column(name = "oauth_provider", nullable = false)
private OAuthProvider oAuthProvider;

public static OAuthInfo create(User user, CommonOAuthInfo commonOAuthInfo) {
return OAuthInfo.builder()
.userId(user.getId())
.oauthId(commonOAuthInfo.oauthId())
.oAuthProvider(commonOAuthInfo.provider())
.build();
}

@Builder
private OAuthInfo(UUID userId, String oauthId, OAuthProvider oAuthProvider) {
this.userId = userId;
this.oauthId = oauthId;
this.oAuthProvider = oAuthProvider;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.somemore.global.auth.oauth;
package com.somemore.global.auth.oauth.domain;

import lombok.Getter;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,65 +1,63 @@
package com.somemore.global.auth.oauth.handler;

import com.somemore.global.auth.cookie.CookieUseCase;
import com.somemore.global.auth.jwt.domain.EncodedToken;
import com.somemore.global.auth.jwt.domain.UserRole;
import com.somemore.global.auth.jwt.usecase.GenerateTokensOnLoginUseCase;
import com.somemore.global.auth.oauth.OAuthProvider;
import com.somemore.global.auth.oauth.naver.service.query.ProcessNaverOAuthUserService;
import com.somemore.global.auth.oauth.processor.OAuthUserProcessor;
import com.somemore.global.auth.redirect.RedirectUseCase;
import com.somemore.domains.volunteer.usecase.VolunteerQueryUseCase;
import com.somemore.user.domain.UserRole;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.UUID;

@Component
@RequiredArgsConstructor
@Slf4j
public class CustomOAuthSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

private final ProcessNaverOAuthUserService processNaverOAuthService;
private final VolunteerQueryUseCase volunteerQueryUseCase;
private final OAuthUserProcessor oauthUserProcessor;
private final GenerateTokensOnLoginUseCase generateTokensOnLoginUseCase;
private final CookieUseCase cookieUseCase;
private final RedirectUseCase redirectUseCase;

@Value("${app.front-url}")
private String frontendRootUrl;
public static final String AUTHORIZATION = "Authorization";
public static final String MAIN_PATH = "/main";

@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
String oAuthId;
switch (getOAuthProvider(authentication)) {
case NAVER -> oAuthId = processNaverOAuthService.processOAuthUser(authentication);
default -> {
log.error("지원하지 않는 OAuth 제공자입니다.");
throw new IllegalArgumentException();
}
}
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) {
OAuth2User oauthUser = extractOAuthUser(authentication);
UUID userId = oauthUserProcessor.fetchUserIdByOAuthUser(oauthUser);

processAccessToken(response, userId);
redirect(request, response);
}

private void redirect(HttpServletRequest request, HttpServletResponse response) {
// TODO 유저 정보 커스텀 확인 분기
redirectUseCase.redirect(request, response, MAIN_PATH);
}

UUID volunteerId = volunteerQueryUseCase.getVolunteerIdByOAuthId(oAuthId);
private void processAccessToken(HttpServletResponse response, UUID userId) {
EncodedToken accessToken =
generateTokensOnLoginUseCase.saveRefreshTokenAndReturnAccessToken(
volunteerId, UserRole.VOLUNTEER
);
userId, UserRole.getOAuthUserDefaultRole());

cookieUseCase.setAccessToken(response, accessToken.value());
redirectUseCase.redirect(request, response, frontendRootUrl);
response.addHeader(AUTHORIZATION, accessToken.getValueWithPrefix());
}

private static OAuthProvider getOAuthProvider(Authentication authentication) {
private OAuth2User extractOAuthUser(Authentication authentication) {
if (authentication instanceof OAuth2AuthenticationToken token) {
return OAuthProvider.from(token.getAuthorizedClientRegistrationId());
return token.getPrincipal();
}
throw new IllegalArgumentException();
log.error("Authentication 객체가 OAuth2AuthenticationToken 타입이 아닙니다: {}", authentication.getClass().getName());
throw new IllegalArgumentException("잘못된 인증 객체입니다.");
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.somemore.global.auth.oauth.naver.dto;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public record NaverUserProfileResponseDto(
String resultcode, // 결과 코드
String message, // 결과 메시지
Response response // 응답 데이터
) {
@JsonIgnoreProperties(ignoreUnknown = true)
public record Response(
String id // 일련 번호
) {
}
}

This file was deleted.

This file was deleted.

Loading
Loading