-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: user 도메인 추가 [#1] * chore: 설정 파일 properties에서 yml로 변경 [#1] * chore: gitignore 수정 [#1] * feat: OAuth 로 리다이렉트하는 uri 추가 [#1] * feat: google oauth client 추가 [#1] * test: 인증 redirect uri 생성 테스트 추가 [#1] * refactor: 소셜 인증 redirect 메서드 이름 변경 [#1] * feat: id token 가져오는 기능 추가 [#1] * test: id token 가져오는 기능 테스트 코드 추가 [#1] * feat: id token에서 유저 정보 가져오는 기능 추가 [#1] * fix: json 매핑 오류 수정 [#1] * test: id token에서 유저 정보 추출 테스트 코드 추가 [#1] * refactor: id token 이미지 받는 기능 제거 및 id token 받는 dto 이름 변경 [#1] * feat: id token의 정보로 유저 엔티티 만드는 기능 추가 [#1] * test: id token 정보로 유저 엔티티 만드는 기능 테스트 코드 추가 [#1] * feat: jwt 토큰 생성 및 파싱 기능 추가 [#1] * test: jwtProvider 테스트 코드 추가 [#1] * refactor: User 도메인 이름 Member로 변경 [#1] * chore: jwt 의존성 추가 [#1] * feat: 로그인 service 추가 [#1] * chore: gitignore 수정 [#1] * test: fixture 추가 및 로그인 service 테스트 코드 추가 [#1] * test: 테스트 코드 fixture 로 변경 [#1] * feat: 로그인 controller 추가 [#1] * refactor: user 패키지 이름 member로 변경 [#1] * feat: 유저 인증 인터셉터 기능 추가 [#1] * test: 인증 헤더 파싱 테스트 코드 추가 [#1] * feat: 예외 관련 처리 구체화 및 advice 추가 [#1] * test: controller 테스트 코드 추가 [#1] * refactor: member 도메인 이름 변경 [#3] * refactor: 예외 구조 변경 [#3] * fix: auth transaction 추가 [#1] * feat: 로컬 이미지 저장 기능 추가 [#3] * feat: 피드 생성 service 기능 추가 [#3] * chore: 개발용 초기화 sql 추가 [#3] * test: 피드 생성 service 테스트 코드 추가 [#3] * fix: 이미지 저장 안되는 버그 수정 [#3] * chore: gitignore 수정 [#3] * feat: 피드 저장 controller 추가 [#3] * test: controller 단위 테스트 용 super class 추가 및 fixture 수정 [#3] * test: 이미지 업로드 단위 테스트 추가 [#3] * chore: memberRepository 패키지 위치 변경 [#3] * style: 안 쓰는 코드 제거 [#3] * feat: 피드 수정 기능 추가 (#6) * test: authControllerTest 단위 테스트로 변경 * feat: 피드 수정 service 추가 * test: 피드 관련 테스트 코드 추가 Closed #5 * feat: 팔로우 언팔로우 기능 추가 (#8) * feat: 팔로우기능 service 추가 * test: 팔로우 service 테스트 코드 추가 * feat: 팔로우 controller 추가 * feat: 언팔로우 기능 service 추가 * test: 언팔로우 serivce 테스트 코드 추가 * feat: 팔로우/언팔로우 controller 추가 * test: 팔로우/언팔로우 controller 테스트 코드 추가 * feat: 피드 수정 기능 추가 (#9) * test: authControllerTest 단위 테스트로 변경 * feat: 피드 수정 service 추가 * test: 피드 관련 테스트 코드 추가 * feat: 피드 수정 controller 추가 * test: 피드 수정 controller 테스트 코드 추가 * feat: 피드 삭제 기능 추가 (#11) * feat: 피드 삭제 기능 추가 * test: 피드 삭제 테스트 코드 추가 * feat: 댓글 생성 기능 추가 (#13) * feat: 댓글 생성 기능 service 추가 * test: 댓글 생성 service 테스트 코드 추가 * feat: 댓글 생성 controller 추가 * test: 댓글 생성 controller 테스트 코드 추가 * fix: 댓글 양방향 관계 추가 및 삭제 시 함께 삭제 되도록 수정 (#16)
- Loading branch information
Showing
81 changed files
with
2,999 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,3 +43,8 @@ out/ | |
*.iml | ||
out | ||
gen | ||
|
||
.DS_Store | ||
src/main/resources/static | ||
src/main/resources/application.yml | ||
data-dev.sql |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
47 changes: 47 additions & 0 deletions
47
src/main/java/com/example/sns/auth/application/AuthService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package com.example.sns.auth.application; | ||
|
||
import com.example.sns.auth.application.dto.OAuthUserInfoDto; | ||
import com.example.sns.auth.infrastructure.GoogleClient; | ||
import com.example.sns.auth.infrastructure.JwtProvider; | ||
import com.example.sns.auth.presentation.dto.TokenResponse; | ||
import com.example.sns.member.domain.Member; | ||
import com.example.sns.member.domain.MemberRepository; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import java.net.URI; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class AuthService { | ||
|
||
private final MemberRepository memberRepository; | ||
private final GoogleClient client; | ||
private final JwtProvider jwtProvider; | ||
|
||
public URI getAuthRedirectURI() { | ||
return client.getAuthRedirectURI(); | ||
} | ||
|
||
@Transactional(readOnly = true) | ||
public TokenResponse signIn(String code) { | ||
OAuthUserInfoDto userInfo = getUserInfo(code); | ||
Member member = memberRepository.findBySocialId(userInfo.getSocialId()) | ||
.orElseGet(() -> signUp(userInfo)); | ||
String token = jwtProvider.createToken(member.getId()); | ||
|
||
return new TokenResponse(token); | ||
} | ||
|
||
private OAuthUserInfoDto getUserInfo(String code) { | ||
String idToken = client.getIdToken(code); | ||
return client.getUserInfo(idToken); | ||
} | ||
|
||
@Transactional | ||
public Member signUp(OAuthUserInfoDto userInfo) { | ||
Member member = Member.createUserFrom(userInfo); | ||
return memberRepository.save(member); | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
src/main/java/com/example/sns/auth/application/dto/OAuthUserInfoDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package com.example.sns.auth.application.dto; | ||
|
||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | ||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@NoArgsConstructor | ||
@AllArgsConstructor | ||
@JsonIgnoreProperties(ignoreUnknown = true) | ||
public class OAuthUserInfoDto { | ||
|
||
private String name; | ||
private String email; | ||
|
||
@JsonProperty("sub") | ||
private String socialId; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package com.example.sns.auth.config; | ||
|
||
import com.example.sns.auth.presentation.AuthArgumentResolver; | ||
import com.example.sns.auth.presentation.AuthInterceptor; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.web.method.support.HandlerMethodArgumentResolver; | ||
import org.springframework.web.reactive.function.client.WebClient; | ||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; | ||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; | ||
|
||
import java.util.List; | ||
|
||
@Configuration | ||
@RequiredArgsConstructor | ||
public class AuthConfig implements WebMvcConfigurer { | ||
|
||
private final AuthProperties properties; | ||
private final AuthInterceptor authInterceptor; | ||
|
||
@Bean | ||
public WebClient oauthProvider() { | ||
return WebClient.create(properties.getTokenUrl()); | ||
} | ||
|
||
@Override | ||
public void addInterceptors(InterceptorRegistry registry) { | ||
registry.addInterceptor(authInterceptor) | ||
.addPathPatterns("/**") | ||
.excludePathPatterns("/auth/**"); | ||
} | ||
|
||
@Override | ||
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { | ||
resolvers.add(new AuthArgumentResolver()); | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
src/main/java/com/example/sns/auth/config/AuthProperties.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package com.example.sns.auth.config; | ||
|
||
import lombok.Getter; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.boot.context.properties.ConfigurationProperties; | ||
import org.springframework.boot.context.properties.ConstructorBinding; | ||
|
||
import java.util.List; | ||
|
||
@Getter | ||
@ConstructorBinding | ||
@RequiredArgsConstructor | ||
@ConfigurationProperties(prefix = "oauth.google") | ||
public class AuthProperties { | ||
|
||
private final String redirectUri; | ||
private final String authUri; | ||
private final String clientId; | ||
private final String clientSecret; | ||
private final String tokenUrl; | ||
private final String grantType; | ||
private final List<String> scopes; | ||
} |
18 changes: 18 additions & 0 deletions
18
src/main/java/com/example/sns/auth/exception/AuthException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package com.example.sns.auth.exception; | ||
|
||
import com.example.sns.common.exception.SnsException; | ||
import lombok.Getter; | ||
import org.springframework.http.HttpStatus; | ||
|
||
@Getter | ||
public class AuthException extends SnsException { | ||
public static final String ERROR_MSG = "예상하지 못한 인증 에러입니다."; | ||
|
||
public AuthException(String errorMsg, HttpStatus status) { | ||
super(errorMsg, status); | ||
} | ||
|
||
public AuthException() { | ||
super(ERROR_MSG, HttpStatus.INTERNAL_SERVER_ERROR); | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
src/main/java/com/example/sns/auth/exception/AuthExtractException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.example.sns.auth.exception; | ||
|
||
import org.springframework.http.HttpStatus; | ||
|
||
public class AuthExtractException extends AuthException { | ||
|
||
public static final String ERROR_MSG = "올바르지 않은 인증 헤더입니다."; | ||
|
||
public AuthExtractException() { | ||
super(ERROR_MSG, HttpStatus.UNAUTHORIZED); | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
src/main/java/com/example/sns/auth/exception/ExpiredTokenException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.example.sns.auth.exception; | ||
|
||
import org.springframework.http.HttpStatus; | ||
|
||
public class ExpiredTokenException extends AuthException { | ||
|
||
public static final String ERROR_MSG = "만료된 토큰입니다."; | ||
|
||
public ExpiredTokenException() { | ||
super(ERROR_MSG, HttpStatus.UNAUTHORIZED); | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
src/main/java/com/example/sns/auth/exception/InvalidTokenException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.example.sns.auth.exception; | ||
|
||
import org.springframework.http.HttpStatus; | ||
|
||
public class InvalidTokenException extends AuthException { | ||
|
||
public static final String ERROR_MSG = "올바르지 않은 토큰입니다."; | ||
|
||
public InvalidTokenException() { | ||
super(ERROR_MSG, HttpStatus.UNAUTHORIZED); | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
src/main/java/com/example/sns/auth/exception/OAuthException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.example.sns.auth.exception; | ||
|
||
import org.springframework.http.HttpStatus; | ||
|
||
public class OAuthException extends AuthException { | ||
|
||
public static final String ERROR_MSG = "OAuth 인증에 실패했습니다."; | ||
|
||
public OAuthException() { | ||
super(ERROR_MSG, HttpStatus.BAD_REQUEST); | ||
} | ||
} |
98 changes: 98 additions & 0 deletions
98
src/main/java/com/example/sns/auth/infrastructure/GoogleClient.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package com.example.sns.auth.infrastructure; | ||
|
||
import com.example.sns.auth.application.dto.OAuthUserInfoDto; | ||
import com.example.sns.auth.config.AuthProperties; | ||
import com.example.sns.auth.exception.AuthException; | ||
import com.example.sns.auth.exception.OAuthException; | ||
import com.example.sns.auth.infrastructure.dto.GoogleAuthResponse; | ||
import com.fasterxml.jackson.core.JsonProcessingException; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.MediaType; | ||
import org.springframework.stereotype.Component; | ||
import org.springframework.util.Base64Utils; | ||
import org.springframework.util.LinkedMultiValueMap; | ||
import org.springframework.util.MultiValueMap; | ||
import org.springframework.web.reactive.function.client.WebClient; | ||
import org.springframework.web.util.UriComponentsBuilder; | ||
|
||
import java.net.URI; | ||
import java.nio.charset.StandardCharsets; | ||
|
||
@Component | ||
@RequiredArgsConstructor | ||
public class GoogleClient { | ||
|
||
private static final int PAYLOAD_INDEX = 1; | ||
private static final String JWT_DELIMITER = "\\."; | ||
private static final String SCOPE_DELIMITER = " "; | ||
private static final String RESPONSE_TYPE = "code"; | ||
|
||
private final AuthProperties properties; | ||
private final WebClient oauthProvider; | ||
private final ObjectMapper objectMapper; | ||
|
||
public URI getAuthRedirectURI() { | ||
MultiValueMap<String, String> parameters = getRedirectParameters(); | ||
return UriComponentsBuilder | ||
.fromUriString(properties.getAuthUri()) | ||
.queryParams(parameters) | ||
.build() | ||
.toUri(); | ||
} | ||
|
||
private MultiValueMap<String, String> getRedirectParameters() { | ||
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>(); | ||
parameters.add("client_id", properties.getClientId()); | ||
parameters.add("redirect_uri", properties.getRedirectUri()); | ||
parameters.add("response_type", RESPONSE_TYPE); | ||
parameters.add("scope", String.join(SCOPE_DELIMITER, properties.getScopes())); | ||
return parameters; | ||
} | ||
|
||
public String getIdToken(String code) { | ||
try { | ||
GoogleAuthResponse googleAuthResponse = oauthProvider.post() | ||
.contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||
.bodyValue(getTokenUriFormData(code)) | ||
.retrieve() | ||
.bodyToMono(GoogleAuthResponse.class) | ||
.block(); | ||
|
||
return googleAuthResponse.getIdToken(); | ||
} catch (NullPointerException e) { | ||
throw new AuthException(); | ||
} catch (Exception e) { | ||
throw new OAuthException(); | ||
} | ||
} | ||
|
||
private MultiValueMap<String, String> getTokenUriFormData(String code) { | ||
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>(); | ||
formData.add("client_id", properties.getClientId()); | ||
formData.add("client_secret", properties.getClientSecret()); | ||
formData.add("grant_type", properties.getGrantType()); | ||
formData.add("redirect_uri", properties.getRedirectUri()); | ||
formData.add("code", code); | ||
return formData; | ||
} | ||
|
||
public OAuthUserInfoDto getUserInfo(String idToken) { | ||
String payload = getPayload(idToken); | ||
String decode = decodeBase64Payload(payload); | ||
|
||
try { | ||
return objectMapper.readValue(decode, OAuthUserInfoDto.class); | ||
} catch (JsonProcessingException e) { | ||
throw new AuthException(); | ||
} | ||
} | ||
|
||
private String getPayload(String idToken) { | ||
return idToken.split(JWT_DELIMITER)[PAYLOAD_INDEX]; | ||
} | ||
|
||
private String decodeBase64Payload(String payload) { | ||
return new String(Base64Utils.decode(payload.getBytes()), StandardCharsets.UTF_8); | ||
} | ||
} |
Oops, something went wrong.