제가 진행하고 있는 곽두철 프로젝트에 Oauth2.0을 사용하여 카카오 로그인을 적용해 보기로 결정했다.
Oauth가 뭐야?
Oauth가 없다고 가정을 해보자.
사용자는 자신의 카카오계정 정보를 제공하기에 부담이 있다.
카카오도 자신들이 관리하는 카카오 계정 정보를 다른 사이트에서도 가지고 있는 건 문제가 있다.
즉, 보안이 취약하다!
Oauth란 무엇일까?
쉽게 말하자면, 우리의 서비스가 우리 서비스를 이용하는 유저의 타사 플랫폼 정보에 접근하기 위해서 권한을 타사 플랫폼으로부터 위임받는 것이다.
이러면 사용자는 카카오에 인증만 하고, 카카오는 곽두철에게 인증된 정보를 가지고 곽두철 프로젝트에 전달해 준다.
카카오 로그인 초기설정
이제 카카오 로그인을 구현하기 위해 카카오 개발자 사이트에 들어간다.
개발자 사이트에 들어간 후, 애플리케이션을 추가한다!
추가한 후, 앱키가 보일 것이다.
저는 여기서 REST API 키를 사용할 것이다. 이건 절대 노출되어선 안된다!
그 이후, 카카오 로그인 탭에 들어가 활성화 설정을 ON으로 바꾼 후, Redirect URI 도 설정한다.
그다음 동의 항목에 들어가 필요한 곳을 체크한다.
동의항목은 이 화면과 같다!
여기까지 카카오 로그인 초기 설정이 끝났다.
카카오 로그인의 큰 틀은 다음과 같이 진행된다
- 카카오 로그인을 한다.
- 인가 코드를 받는다.
- 인가 코드를 가지고 토큰을 발급받는다.
- 토큰으로 유저의 정보를 가져온다.
이제 구현을 시작해 보겠다!
1. 인가 코드 받기
카카오에서 지정한 형식이 있다.
- client_id : 내 앱 키에서 REST API 키
- redirect_uri : 리다이렉트 URI에 추가한 주소
- response_type은 code로 고정
여기 code 뒤에 있는 것이 인가 코드이다.
2. 토큰 발급
앞서 받은 code로 토큰을 발급받는 Service이다.
@Component
public class KakaoLoginTokenClient {
private final WebClient webClient;
@Value("${token.uri}")
private String TOKEN_URI;
@Value("${redirect.uri}")
private String REDIRECT_URI;
@Value("${grant.type}")
private String GRANT_TYPE;
@Value("${client.id}")
private String CLIENT_ID;
public KakaoLoginTokenClient() {
this.webClient = WebClient.create();
}
public KakaoTokenResponse getTokenInfo(final String code) {
final String uri = UriComponentsBuilder.fromUriString(TOKEN_URI)
.queryParam("grant_type", GRANT_TYPE)
.queryParam("client_id", CLIENT_ID)
.queryParam("redirect_uri", REDIRECT_URI)
.queryParam("code", code)
.toUriString();
Flux<KakaoTokenResponse> response = webClient.post()
.uri(uri)
.contentType(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToFlux(KakaoTokenResponse.class);
return response.blockFirst();
}
}
여기서
Client_Id는 애플리케이션의 REST API KEY이다.
token.uri는 https://kauth.kakao.com/oauth/token이며
grant.type은 authorization_code이고
redirect_uri는 초기 설정할 때 입력한 값이다.
3. 유저 정보 받기
@Component
public class KakaoLoginUserClient {
private final WebClient webClient;
private static final String USER_INFO_URI = "<https://kapi.kakao.com/v2/user/me>";
public KakaoLoginUserClient() {
this.webClient = WebClient.create(USER_INFO_URI);
}
public KakaoUserInfoResponse getUserInfo(final String token) {
Flux response = webClient.get()
.header("Authorization", "Bearer " + token)
.retrieve()
.bodyToFlux(KakaoUserInfoResponse.class);
return response.blockFirst();
}
}
KakaoLoginUserClient의 getUserInfo를 통해 유저 정보를 받아올 수 있다.
4. AuthService
@Service
@RequiredArgsConstructor
@Slf4j
public class AuthService {
private final KakaoLoginTokenClient kakaoLoginTokenClient;
private final KakaoLoginUserClient kakaoLoginUserClient;
private final JwtProvider jwtProvider;
private final UserRepository userRepository;
public String login(final LoginRequest request) {
final KakaoTokenResponse kakaoTokenResponse = kakaoLoginTokenClient.getTokenInfo(request.authorizationCode());
final KakaoUserInfoResponse userInfo = kakaoLoginUserClient.getUserInfo(kakaoTokenResponse.access_token());
final User user = userRepository.findBySocialIdAndSocialType(userInfo.id(), request.socialType())
.orElseGet(() -> initUser(userInfo, userInfo.id()));
final String jwtToken = jwtProvider.createToken(user.getId());
log.info("User 로그인 성공: {} ", user);
return jwtToken;
}
private User initUser(final KakaoUserInfoResponse userInfo, final Long socialId) {
final User user = User.of(socialId.toString(), userInfo.getName());
return userRepository.save(user);
}
}
토큰을 발급받고 그 토큰으로 유저를 받아와 저장하는 Service이다.
이제 카카오 로그인한 유저 정보를 알 수 있게 됐다.
'WEB' 카테고리의 다른 글
Redis 내부동작 파헤치기 (0) | 2024.05.05 |
---|---|
Redis Lock 동시성 해결하기 (0) | 2024.05.01 |
인터셉터와 리졸버 (0) | 2024.04.12 |
JWT 활용기 (0) | 2024.04.12 |
리사이징 적용기 with Marvin (0) | 2024.03.14 |
Spring Cloud Config 도입기 (0) | 2024.03.08 |
OAuth 2.0 동작 방식 (0) | 2023.06.05 |
JPA란 무엇일까? (0) | 2023.06.01 |