공부일기
NAVER LOGIN API 연동
Youngbin Kim
2021. 7. 19. 17:01
기본 정보
- Client ID
- Client Secret
- 서비스 URL
- Callback URL
- State
소셜로그인의 과정
소셜로그인의 과정은 크게 3가지로 볼 수 있다.
- 인가코드 받기
- 토큰 받기
- 리소스(회원정보) 받기
- 인가코드 받기
네이버 개발자센터를 통해 서비스를 등록하고, Client ID와 Client Secret을 발급 받는다.
네이버로부터 제공받고자 하는 사용자 정보를 필수, 추가 설정으로 받아올 수 있다.
일단 개발환경에서 테스트할 예정이기 때문에 localhost:8080으로 지정했다.
설정 후 확인을 누르면 네이버에서 Client ID와 Client Secret을 발급해준다.
- Client Secret의 경우 외부에 노출되어선 안 된다.
서비스의 Client ID, redirect_uri(Callback URL의 인코딩 값), state(상태 유지를 위한 임의의 문자열) 정보를 넣어 아래 예제와 같은 주소로 요청을 보낸다.
https://nid.naver.com/oauth2.0/authorize?response_type=code&client_id={}&redirect_uri={}&state={}
로그인하게 되면 아래처럼 필수로 선택해 놓은 항목들을 서비스에 제공하는 데 동의하는 지 묻는다.
동의하기를 누르면 사진처럼 설정해놓은 Callback URL로 이동한다. 이 때 네이버에서 url 파라미터로 code를 제공해주는 것을 확인할 수 있다.
2. 토큰 받기
제공 받은 인가코드(code)를 백엔드쪽에 넘기고, Resource Server(NAVER)에게 토큰을 받아와야 한다.
발급 받은 code와 status 값을 이용해 네이버에게 토큰 발급을 요청한다.
@RequestMapping("/auth/naver/login/callback")
public ResponseEntity naverCallback(String code, String state) throws JsonProcessingException {
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("grant_type","authorization_code");
params.add("client_id",CLIENT_ID);
params.add("client_secret", CLIENT_SECRET);
params.add("code", code);
params.add("state", state);
// Parameter로 전달할 속성들 추가
HttpEntity<MultiValueMap<String, String>> naverTokenRequest = makeTokenRequest(params);
// Http 메시지 생성
RestTemplate rt = new RestTemplate();
ResponseEntity<String> tokenResponse = rt.exchange(
TOKEN_REQUEST_URL,
HttpMethod.POST,
naverTokenRequest,
String.class
);
// TOKEN_REQUEST_URL로 Http 요청 전송
ObjectMapper objectMapper = new ObjectMapper();
NaverOAuthToken naverToken = objectMapper.readValue(tokenResponse.getBody(), NaverOAuthToken.class);
// ObjectMapper를 통해 NaverOAuthToken 객체로 매핑
}
private HttpEntity<MultiValueMap<String, String>> makeTokenRequest(MultiValueMap<String, String> params) {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");
HttpEntity<MultiValueMap<String, String>> naverTokenRequest = new HttpEntity<>(params, headers);
return naverTokenRequest;
}
public class NaverOAuthToken {
private String access_token;
private String refresh_token;
private String token_type;
private String expires_in;
public NaverOAuthToken() {
}
public String getAccess_token() {
return access_token;
}
...
public void setExpires_in(String expires_in) {
this.expires_in = expires_in;
}
}
3. 리소스 받기(회원정보 받기)
네이버에서 받아온 토큰 정보를 활용해 회원 프로필 조회 API를 호출한다.
응답을 마찬가지로 회원정보 객체에 매핑시킨다.
@RequestMapping("/auth/naver/login/callback")
public ResponseEntity naverCallback(String code, String state) throws JsonProcessingException {
...
HttpEntity<MultiValueMap<String, String>> naverProfileRequest = makeProfileRequest(naverToken);
ResponseEntity<String> profileResponse = rt.exchange(
PROFILE_REQUEST_URL,
HttpMethod.POST,
naverProfileRequest,
String.class
);
NaverProfileResponse naverProfileResponse = objectMapper.readValue(profileResponse.getBody(), NaverProfileResponse.class);
}
private HttpEntity<MultiValueMap<String, String>> makeProfileRequest(NaverOAuthToken naverToken) {
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Bearer "+ naverToken.getAccess_token());
headers.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");
HttpEntity<MultiValueMap<String, String>> naverProfileRequest = new HttpEntity<>(headers);
return naverProfileRequest;
}
public class NaverProfileResponse {
private String resultcode;
private String message;
private NaverProfile response;
public NaverProfileResponse() {
}
public String getResultcode() {
return resultcode;
}
...
public void setResponse(NaverProfile response) {
this.response = response;
}
}
public class NaverProfile {
private String email;
private String nickname;
private String profile_image;
private String age;
private String gender;
private String id;
private String name;
private String birthday;
private String birthyear;
private String mobile;
public NaverProfile() {
}
public String getEmail() {
return email;
}
...
public void setMobile(String mobile) {
this.mobile = mobile;
}
}
이후의 과정은
- 서비스 고유의 토큰 생성
- 레이어 분리(컨틀로러-서비스-레파지토리)
등으로 이뤄질 것 같다.