-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: OAuth 요청에 대한 응답 DTO 작성 * chore: Jasypt 의존성 추가 * feat: 카카오 OAuth Client 객체 구현 * feat: OAuthProvider 구현 * feat: Login 서비스, 컨트롤러 구현 * feat: 소셜 로그인 회원가입 분기 흐름 구현 * feat: jwt를 통한 로그인 기능 구현 * chore: 디버깅 출력 문구 삭제 * fix: jasypt 시크릿 키를 github action에서 환경 변수로 지정 * fix: github action에서 빌드 시 jasypt secret key를 환경변수로 받도록 변경 - `build.gradle`에 테스트 시 jasypt secret key를 환경변수로 지정한다. - `be-cd-dev.yml`와 `be-ci.yml`에서 -P 옵션으로 jasypt secret key를 환경변수로 지정한다. * feat: 카카오 OAuth 로그인 redirect uri 프로파일별로 분리 * fix: 테스트 용 config yml 파일 분리 및 테스트에서 jasypt 제거 * chore: 로컬용 jwt 비밀키와 개발 서버용 키 분리 * chore: 데이터베이스 정보 관리 환경변수 방식에서 jasypt 방식으로 변경 * refactor: DTO inner 클래스 가독성 위해서 별도의 record로 분리 * refactor: 카카오 유저 정보 응답 DTO nested record로 개선 * style: 괄호 재배치, 공백 문자 가독성 개선 * refactor: RestClient 설정 기능 생성자에서 분리 개선 * refactor: 하드 코딩된 헤더 정보 미리 제공되는 상수로 변경 * refactor: 사용되지 않는 생성자 접근 제어 레벨 개선 * chore: github action에서 빌드 시 환경 변수를 지정하지 않도록 변경 --------- Co-authored-by: libienz <[email protected]> Co-authored-by: nhlee98 <[email protected]> Co-authored-by: 이낙헌 <[email protected]>
- Loading branch information
1 parent
ebe87b2
commit 872557a
Showing
18 changed files
with
362 additions
and
47 deletions.
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
24 changes: 24 additions & 0 deletions
24
backend/src/main/java/woowacourse/touroot/authentication/controller/LoginController.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,24 @@ | ||
package woowacourse.touroot.authentication.controller; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RequestParam; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import woowacourse.touroot.authentication.dto.LoginResponse; | ||
import woowacourse.touroot.authentication.service.LoginService; | ||
|
||
@RequiredArgsConstructor | ||
@RestController | ||
@RequestMapping("/api/v1/login") | ||
public class LoginController { | ||
|
||
private final LoginService loginService; | ||
|
||
@GetMapping("/oauth/kakao") | ||
public ResponseEntity<LoginResponse> login(@RequestParam(name = "code") String authorizationCode) { | ||
return ResponseEntity.ok() | ||
.body(loginService.login(authorizationCode)); | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
backend/src/main/java/woowacourse/touroot/authentication/dto/KakaoAccessTokenResponse.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,19 @@ | ||
package woowacourse.touroot.authentication.dto; | ||
|
||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
|
||
public record KakaoAccessTokenResponse( | ||
@JsonProperty("token_type") | ||
String tokenType, | ||
@JsonProperty("access_token") | ||
String accessToken, | ||
@JsonProperty("expires_in") | ||
Integer expiresIn, | ||
@JsonProperty("refresh_token") | ||
String refreshToken, | ||
@JsonProperty("refresh_token_expires_in") | ||
Integer refreshTokenExpiresIn, | ||
@JsonProperty("scope") | ||
String scope | ||
) { | ||
} |
4 changes: 4 additions & 0 deletions
4
backend/src/main/java/woowacourse/touroot/authentication/dto/LoginResponse.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,4 @@ | ||
package woowacourse.touroot.authentication.dto; | ||
|
||
public record LoginResponse(String accessToken) { | ||
} |
30 changes: 30 additions & 0 deletions
30
...nd/src/main/java/woowacourse/touroot/authentication/dto/OauthUserInformationResponse.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,30 @@ | ||
package woowacourse.touroot.authentication.dto; | ||
|
||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
|
||
public record OauthUserInformationResponse( | ||
@JsonProperty("id") | ||
Long socialLoginId, | ||
@JsonProperty("kakao_account") | ||
KakaoAccount kakaoAccount | ||
) { | ||
|
||
public String nickname() { | ||
return kakaoAccount.kakaoProfile.nickname; | ||
} | ||
|
||
public String profileImage() { | ||
return kakaoAccount.kakaoProfile.image; | ||
} | ||
|
||
private record KakaoAccount( | ||
@JsonProperty("profile") KakaoProfile kakaoProfile | ||
) { | ||
} | ||
|
||
private record KakaoProfile( | ||
@JsonProperty("nickname") String nickname, | ||
@JsonProperty("profile_image_url") String image | ||
) { | ||
} | ||
} |
37 changes: 37 additions & 0 deletions
37
...end/src/main/java/woowacourse/touroot/authentication/infrastructure/JwtTokenProvider.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,37 @@ | ||
package woowacourse.touroot.authentication.infrastructure; | ||
|
||
import io.jsonwebtoken.Jwts; | ||
import io.jsonwebtoken.security.Keys; | ||
import java.util.Date; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.stereotype.Component; | ||
import woowacourse.touroot.member.domain.Member; | ||
|
||
@Component | ||
public class JwtTokenProvider { | ||
|
||
private static final String MEMBER_ID_KEY = "id"; | ||
|
||
private final String secretKey; | ||
private final long validityInMilliseconds; | ||
|
||
public JwtTokenProvider( | ||
@Value("${security.jwt.token.secret-key}") String secretKey, | ||
@Value("${security.jwt.token.expire-length}") long validityInMilliseconds | ||
) { | ||
this.secretKey = secretKey; | ||
this.validityInMilliseconds = validityInMilliseconds; | ||
} | ||
|
||
public String createToken(Member member) { | ||
Date now = new Date(); | ||
Date validity = new Date(now.getTime() + validityInMilliseconds); | ||
|
||
return Jwts.builder() | ||
.setSubject(member.getId().toString()) | ||
.claim(MEMBER_ID_KEY, member.getId()) | ||
.setExpiration(validity) | ||
.signWith(Keys.hmacShaKeyFor(secretKey.getBytes())) | ||
.compact(); | ||
} | ||
} |
77 changes: 77 additions & 0 deletions
77
...end/src/main/java/woowacourse/touroot/authentication/infrastructure/KakaoOauthClient.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,77 @@ | ||
package woowacourse.touroot.authentication.infrastructure; | ||
|
||
import java.time.Duration; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.boot.web.client.ClientHttpRequestFactories; | ||
import org.springframework.boot.web.client.ClientHttpRequestFactorySettings; | ||
import org.springframework.http.HttpHeaders; | ||
import org.springframework.http.MediaType; | ||
import org.springframework.http.client.ClientHttpRequestFactory; | ||
import org.springframework.stereotype.Component; | ||
import org.springframework.util.LinkedMultiValueMap; | ||
import org.springframework.util.MultiValueMap; | ||
import org.springframework.web.client.RestClient; | ||
import woowacourse.touroot.authentication.dto.KakaoAccessTokenResponse; | ||
import woowacourse.touroot.authentication.dto.OauthUserInformationResponse; | ||
|
||
@Component | ||
public class KakaoOauthClient { | ||
|
||
private final String userInformationRequestUri; | ||
private final String accessTokenRequestUri; | ||
private final String restApiKey; | ||
private final String redirectUri; | ||
private final RestClient restClient; | ||
|
||
public KakaoOauthClient( | ||
@Value("${oauth.kakao.user-information-request-uri}") String userInformationRequestUri, | ||
@Value("${oauth.kakao.access-token-request-uri}") String accessTokenRequestUri, | ||
@Value("${oauth.kakao.rest-api-key}") String restApiKey, | ||
@Value("${oauth.kakao.redirect-uri}") String redirectUri | ||
) { | ||
this.userInformationRequestUri = userInformationRequestUri; | ||
this.accessTokenRequestUri = accessTokenRequestUri; | ||
this.restApiKey = restApiKey; | ||
this.redirectUri = redirectUri; | ||
this.restClient = buildRestClient(); | ||
} | ||
|
||
private RestClient buildRestClient() { | ||
ClientHttpRequestFactorySettings settings = ClientHttpRequestFactorySettings.DEFAULTS | ||
.withConnectTimeout(Duration.ofSeconds(1)) | ||
.withReadTimeout(Duration.ofSeconds(3)); | ||
|
||
ClientHttpRequestFactory requestFactory = ClientHttpRequestFactories.get(settings); | ||
|
||
return RestClient.builder() | ||
.requestFactory(requestFactory) | ||
.build(); | ||
} | ||
|
||
public OauthUserInformationResponse requestUserInformation(String authorizationCode) { | ||
KakaoAccessTokenResponse kakaoAccessTokenResponse = requestAccessToken(authorizationCode); | ||
|
||
return restClient.get() | ||
.uri(userInformationRequestUri) | ||
.header(HttpHeaders.AUTHORIZATION, "Bearer " + kakaoAccessTokenResponse.accessToken()) | ||
.retrieve() | ||
.toEntity(OauthUserInformationResponse.class) | ||
.getBody(); | ||
} | ||
|
||
private KakaoAccessTokenResponse requestAccessToken(String authorizationCode) { | ||
MultiValueMap<String, String> params = new LinkedMultiValueMap<>(); | ||
params.add("code", authorizationCode); | ||
params.add("client_id", restApiKey); | ||
params.add("redirect_uri", redirectUri); | ||
params.add("grant_type", "authorization_code"); | ||
|
||
return restClient.post() | ||
.uri(accessTokenRequestUri) | ||
.contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||
.body(params) | ||
.retrieve() | ||
.toEntity(KakaoAccessTokenResponse.class) | ||
.getBody(); | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
...d/src/main/java/woowacourse/touroot/authentication/infrastructure/KakaoOauthProvider.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,16 @@ | ||
package woowacourse.touroot.authentication.infrastructure; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Component; | ||
import woowacourse.touroot.authentication.dto.OauthUserInformationResponse; | ||
|
||
@RequiredArgsConstructor | ||
@Component | ||
public class KakaoOauthProvider { | ||
|
||
private final KakaoOauthClient kakaoOauthClient; | ||
|
||
public OauthUserInformationResponse getUserInformation(String authorizationCode) { | ||
return kakaoOauthClient.requestUserInformation(authorizationCode); | ||
} | ||
} |
33 changes: 33 additions & 0 deletions
33
backend/src/main/java/woowacourse/touroot/authentication/service/LoginService.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,33 @@ | ||
package woowacourse.touroot.authentication.service; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import woowacourse.touroot.authentication.dto.LoginResponse; | ||
import woowacourse.touroot.authentication.dto.OauthUserInformationResponse; | ||
import woowacourse.touroot.authentication.infrastructure.JwtTokenProvider; | ||
import woowacourse.touroot.authentication.infrastructure.KakaoOauthProvider; | ||
import woowacourse.touroot.member.domain.Member; | ||
import woowacourse.touroot.member.repository.MemberRepository; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class LoginService { | ||
|
||
private final MemberRepository memberRepository; | ||
private final KakaoOauthProvider oauthProvider; | ||
private final JwtTokenProvider tokenProvider; | ||
|
||
public LoginResponse login(String code) { | ||
OauthUserInformationResponse userInformation = oauthProvider.getUserInformation(code); | ||
Member member = memberRepository.findByKakaoId(userInformation.socialLoginId()) | ||
.orElseGet(() -> signUp(userInformation)); | ||
|
||
return new LoginResponse(tokenProvider.createToken(member)); | ||
} | ||
|
||
private Member signUp(OauthUserInformationResponse userInformation) { | ||
return memberRepository.save( | ||
new Member(userInformation.socialLoginId(), userInformation.nickname(), userInformation.profileImage()) | ||
); | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
backend/src/main/java/woowacourse/touroot/global/config/JasyptConfig.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,9 @@ | ||
package woowacourse.touroot.global.config; | ||
|
||
import com.ulisesbocchio.jasyptspringboot.annotation.EnableEncryptableProperties; | ||
import org.springframework.context.annotation.Configuration; | ||
|
||
@Configuration | ||
@EnableEncryptableProperties | ||
public class JasyptConfig { | ||
} |
36 changes: 36 additions & 0 deletions
36
backend/src/main/java/woowacourse/touroot/member/domain/Member.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,36 @@ | ||
package woowacourse.touroot.member.domain; | ||
|
||
import jakarta.persistence.Column; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.GenerationType; | ||
import jakarta.persistence.Id; | ||
import lombok.AccessLevel; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
import woowacourse.touroot.entity.BaseEntity; | ||
|
||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
@AllArgsConstructor(access = AccessLevel.PRIVATE) | ||
@Getter | ||
@Entity | ||
public class Member extends BaseEntity { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
|
||
@Column(nullable = false) | ||
private Long kakaoId; | ||
|
||
@Column(nullable = false) | ||
private String nickname; | ||
|
||
@Column(nullable = false) | ||
private String profileImageUri; | ||
|
||
public Member(Long kakaoId, String nickname, String profileImageUri) { | ||
this(null, kakaoId, nickname, profileImageUri); | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
backend/src/main/java/woowacourse/touroot/member/repository/MemberRepository.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,10 @@ | ||
package woowacourse.touroot.member.repository; | ||
|
||
import java.util.Optional; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import woowacourse.touroot.member.domain.Member; | ||
|
||
public interface MemberRepository extends JpaRepository<Member, Long> { | ||
|
||
Optional<Member> findByKakaoId(Long kakaoId); | ||
} |
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
Oops, something went wrong.