-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[LIME-122] 카카오 소셜 로그인 처리 방식 수정 #63
Changes from 13 commits
8695497
285f2a4
17d4d60
098c363
71911d1
e145506
5d9ba7d
9c935dd
79aa60c
9dd6d04
68683b6
f2332eb
188a92a
05d9cf0
2f94280
852f50e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package com.programmers.lime.domains.auth.api; | ||
|
||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.RequestParam; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
import com.programmers.lime.domains.auth.application.OAuthUserService; | ||
import com.programmers.lime.domains.member.api.dto.response.MemberLoginResponse; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@RequiredArgsConstructor | ||
@RestController | ||
public class AuthController { | ||
|
||
private final OAuthUserService oauthUserService; | ||
|
||
@GetMapping("/auth/kakao/callback") | ||
public ResponseEntity<MemberLoginResponse> loginKakao( | ||
@RequestParam final String code | ||
) { | ||
return ResponseEntity.ok(oauthUserService.login(code)); | ||
} | ||
|
||
@GetMapping("/join") | ||
public ResponseEntity<String> join(){ | ||
return ResponseEntity.ok("join"); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package com.programmers.lime.domains.auth.api.dto; | ||
|
||
import static com.programmers.lime.domains.member.domain.vo.SocialType.*; | ||
|
||
import java.util.UUID; | ||
|
||
import com.fasterxml.jackson.databind.PropertyNamingStrategies; | ||
import com.fasterxml.jackson.databind.annotation.JsonNaming; | ||
import com.programmers.lime.domains.member.domain.Member; | ||
import com.programmers.lime.domains.member.domain.vo.Role; | ||
import com.programmers.lime.domains.member.domain.vo.SocialInfo; | ||
|
||
@JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class) | ||
public record KakaoMemberResponse( | ||
Long id, //카카오 소셜 id | ||
|
||
KakaoAccount kakaoAccount | ||
|
||
) { | ||
@JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class) | ||
public record KakaoAccount( | ||
String email, | ||
Profile profile | ||
) { | ||
@JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class) | ||
public record Profile( | ||
String profileImageUrl | ||
) { | ||
} | ||
} | ||
|
||
public Member toEntity(){ | ||
SocialInfo socialInfo = SocialInfo.builder() | ||
.socialId(this.id) | ||
.email(this.kakaoAccount.email) | ||
.profileImage(this.kakaoAccount.profile.profileImageUrl) | ||
.role(Role.GUEST) | ||
.socialType(KAKAO) | ||
.build(); | ||
|
||
long timestamp = System.currentTimeMillis(); | ||
String randomString = String.valueOf(UUID.randomUUID()).replace("-", "").substring(0, 8); | ||
String randomNickname = timestamp + randomString; | ||
|
||
return new Member(socialInfo, randomNickname); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.programmers.lime.domains.auth.api.dto; | ||
|
||
import org.springframework.boot.context.properties.ConfigurationProperties; | ||
|
||
@ConfigurationProperties(prefix = "oauth.kakao.login") | ||
public record KakaoOAuthLoginInfo( | ||
String grantType, | ||
String clientId, | ||
String clientSecret, | ||
String redirectUri | ||
) { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package com.programmers.lime.domains.auth.api.dto; | ||
|
||
import com.fasterxml.jackson.databind.PropertyNamingStrategies; | ||
import com.fasterxml.jackson.databind.annotation.JsonNaming; | ||
|
||
@JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class) | ||
public record OAuthAccessTokenResponse( | ||
String tokenType, | ||
String accessToken, | ||
Integer expiresIn, | ||
String refreshToken, | ||
Integer refreshTokenExpiresIn | ||
) { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package com.programmers.lime.domains.auth.application; | ||
|
||
import org.springframework.http.HttpEntity; | ||
import org.springframework.http.HttpHeaders; | ||
import org.springframework.http.HttpMethod; | ||
import org.springframework.http.MediaType; | ||
import org.springframework.stereotype.Component; | ||
import org.springframework.util.LinkedMultiValueMap; | ||
import org.springframework.util.MultiValueMap; | ||
import org.springframework.web.client.RestTemplate; | ||
|
||
import com.programmers.lime.domains.auth.api.dto.KakaoMemberResponse; | ||
import com.programmers.lime.domains.auth.api.dto.KakaoOAuthLoginInfo; | ||
import com.programmers.lime.domains.auth.api.dto.OAuthAccessTokenResponse; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
|
||
@Component | ||
@RequiredArgsConstructor | ||
public class KakaoOAuthClient { | ||
|
||
private static final RestTemplate restTemplate = new RestTemplate(); | ||
private final KakaoOAuthLoginInfo kakaoOAuthLoginInfo; | ||
|
||
public String getAccessToken(final String code) { | ||
MultiValueMap<String, String> loginInfoRequest = makeKakaoLoginInfo(code); | ||
HttpHeaders headers = new HttpHeaders(); | ||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); | ||
|
||
HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(loginInfoRequest, headers); | ||
|
||
OAuthAccessTokenResponse response = restTemplate.postForEntity( | ||
"https://kauth.kakao.com/oauth/token", | ||
httpEntity, | ||
OAuthAccessTokenResponse.class | ||
).getBody(); | ||
|
||
return response.accessToken(); | ||
} | ||
|
||
private MultiValueMap<String, String> makeKakaoLoginInfo(final String code) { | ||
MultiValueMap<String, String> loginInfoRequest = new LinkedMultiValueMap<>(); | ||
|
||
loginInfoRequest.add("grant_type", kakaoOAuthLoginInfo.grantType()); | ||
loginInfoRequest.add("client_id", kakaoOAuthLoginInfo.clientId()); | ||
loginInfoRequest.add("client_secret", kakaoOAuthLoginInfo.clientSecret()); | ||
loginInfoRequest.add("redirect_uri", kakaoOAuthLoginInfo.redirectUri()); | ||
loginInfoRequest.add("code", code); | ||
|
||
return loginInfoRequest; | ||
} | ||
|
||
public KakaoMemberResponse getMemberInfo(final String accessToken) { | ||
HttpHeaders headers = new HttpHeaders(); | ||
headers.setBearerAuth(accessToken); | ||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); | ||
|
||
HttpEntity<Void> request = new HttpEntity<>(headers); | ||
|
||
KakaoMemberResponse response = restTemplate.exchange( | ||
"https://kapi.kakao.com/v2/user/me", | ||
HttpMethod.GET, | ||
request, | ||
KakaoMemberResponse.class | ||
).getBody(); | ||
|
||
return response; | ||
} | ||
|
||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package com.programmers.lime.domains.auth.application; | ||
|
||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import com.programmers.lime.domains.auth.api.dto.KakaoMemberResponse; | ||
import com.programmers.lime.domains.member.api.dto.response.MemberLoginResponse; | ||
import com.programmers.lime.domains.member.domain.Member; | ||
import com.programmers.lime.domains.member.domain.vo.SocialType; | ||
import com.programmers.lime.domains.member.implementation.MemberAppender; | ||
import com.programmers.lime.domains.member.implementation.MemberReader; | ||
import com.programmers.lime.global.config.security.jwt.JwtService; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class OAuthUserService { | ||
|
||
private final KakaoOAuthClient kakaoOAuthClient; | ||
private final MemberAppender memberAppender; | ||
private final MemberReader memberReader; | ||
private final JwtService jwtService; | ||
|
||
@Transactional | ||
public MemberLoginResponse login(String code) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. p1; There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 2f94280 반영 완료 |
||
String kakaoAccessToken = kakaoOAuthClient.getAccessToken(code); | ||
KakaoMemberResponse response = kakaoOAuthClient.getMemberInfo(kakaoAccessToken); | ||
|
||
Member foundMember = memberReader.readBySocialIdAndSocialType( | ||
response.id(), | ||
SocialType.KAKAO | ||
).orElseGet(() -> saveMember(response)); | ||
|
||
String accessToken = jwtService.generateAccessToken(String.valueOf(foundMember.getId())); | ||
String refreshToken = jwtService.generateRefreshToken(); | ||
|
||
return MemberLoginResponse.from(foundMember, accessToken, refreshToken); | ||
} | ||
|
||
private Member saveMember(final KakaoMemberResponse response) { | ||
return memberAppender.append(response.toEntity()); | ||
} | ||
|
||
} |
This file was deleted.
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
p5; (단순 궁금)
오 카카오 로그인 과정에서는 snake case로 통신하나요?!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이거는 카카오 개발자 센터에서 제공해주는 정해진 양식이 snakeCase이기 때문에 그 형식에 맞춰 전달해줘야만 합니다~