์ด๋ฒ์๋ ๋ค์ด๋ฒ ์์ด๋๋ก ๋ก๊ทธ์ธ(๋ค์๋ก) ๋ฅผ ๊ตฌํํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
์ฐธ๊ณ :
- ๊ตฌ๊ธ ๊ณ์ ์ผ๋ก ๋ก๊ทธ์ธ์ ์ฌ๊ธฐ๋ฅผ ์ฐธ์กฐํ์๊ธฐ ๋ฐ๋๋๋ค.
- ์นด์นด์ค ๊ณ์ ์ผ๋ก ๋ก๊ทธ์ธ์ ์ฌ๊ธฐ๋ฅผ ์ฐธ์กฐํ์๊ธฐ ๋ฐ๋๋๋ค.
- ์์ ๋ก๊ทธ์ธ์ ํ๊ธฐ์ํด ํ์ํ API ํค ๋ฐ๊ธ์ ์ฌ๊ธฐ๋ฅผ ์ฐธ์กฐํ์๊ธฐ ๋ฐ๋๋๋ค.
1. ๋ค์๋ก ์ฐ๋ URL ์์ฒญ
์๋์ฒ๋ผ ์ํ๋ ํ๊ทธ์ ์์ฒญ URL์ ์์ฑ ์์ผ์ ๋ฃ์ด์ฃผ๋๋ก ํฉ๋๋ค. (state๋ ์๋ ๊ณ์ ๋๋ค์ผ๋ก ์์ฑํด์ฃผ์ด์ผ ํ๋๋ฐ, ์ฌ๊ธฐ์๋ ํ ์คํธ๋ฅผ ์ํด "state"๋ผ๋ ๊ฐ์ผ๋ก ํ๊ฒ ์ต๋๋ค.)
<a href="https://nid.naver.com/oauth2.0/authorize?response_type=code&client_id=CLIENT_ID&state=state&redirect_uri=CALLBACK_URL">๋ค์ด๋ฒ๋ก ๋ก๊ทธ์ธ ํ๊ธฐ</a>
2. Redirect URI ์ฒ๋ฆฌํ๋ ์ปจํธ๋กค๋ฌ ์์ฑ
์ ๋ ์ ํ๋ฆฌ์ผ์ด์ ์์ Redirect URI๋ฅผ "/login/oauth/code/naver"๋ก ์ค์ ํ์ต๋๋ค.
@Controller
@RequestMapping("/login/oauth/code")
public class OAuthTestController {
... ์๋ต ...
@GetMapping("/naver")
@ResponseBody
public String naverOAuthRedirect(@RequestParam String code, @RequestParam String state) {
// state๋ ๋ฌด์ํ๊ฒ ์ต๋๋ค.
return "code : " + code;
}
์ด๋ ๊ฒ ๋๋ฉด ๋ด๊ฐ ์ค์ ํด๋์ URI๋ก ์๋ต์ด ์ค๊ฒ ๋๊ณ , ์ด ์ปจํธ๋กค๋ฌ์์ ์ฒ๋ฆฌํ๊ฒ ๋ฉ๋๋ค. ๊ทธ๋ผ ์ ์์ ์ผ๋ก ์๋์ฒ๋ผ ์ฝ๋๊ฐ ์ฐํ๊ฒ ๋ฉ๋๋ค.
Response:
code : {code}
3. ์ธ์ฆ ํ ํฐ์ผ๋ก Access Token์ผ๋ก ๊ตํํ๊ธฐ
์์ฒญ์ ์๋์ ๊ฐ์ด MultiValueMap์ key:value ํ์์ผ๋ก ๊ฐ์ ๋ฃ์ด์ค์ ์์ฒญ ํ์๋ฉด ๋๊ฒ ์ต๋๋ค.
Request :
@GetMapping("/naver")
@ResponseBody
public String naverOAuthRedirect(@RequestParam String code, @RequestParam String state) {
// RestTemplate ์ธ์คํด์ค ์์ฑ
RestTemplate rt = new RestTemplate();
HttpHeaders accessTokenHeaders = new HttpHeaders();
accessTokenHeaders.add("Content-type", "application/x-www-form-urlencoded");
MultiValueMap<String, String> accessTokenParams = new LinkedMultiValueMap<>();
accessTokenParams.add("grant_type", "authorization_code");
accessTokenParams.add("client_id", "{client_id");
accessTokenParams.add("client_secret", "{client_secret}");
accessTokenParams.add("code" , code); // ์๋ต์ผ๋ก ๋ฐ์ ์ฝ๋
accessTokenParams.add("state" , state); // ์๋ต์ผ๋ก ๋ฐ์ ์ํ
HttpEntity<MultiValueMap<String, String>> accessTokenRequest = new HttpEntity<>(accessTokenParams, accessTokenHeaders);
ResponseEntity<String> accessTokenResponse = rt.exchange(
"https://nid.naver.com/oauth2.0/token",
HttpMethod.POST,
accessTokenRequest,
String.class
);
return "accessToken: " + accessTokenResponse.getBody();
}
}
Response :
access token ๋ฐ๊ธ ์๋ฃ!! ๐
4. Access Token์ ์ด์ฉํด ํ๋กํ API ํธ์ถํ๊ธฐ
ํค๋์๋ง Authorization ๊ฐ๋ง ๋ฃ์ด์ฃผ๋ฉด ๋๋ ๊ฒ ๊ฐ์ต๋๋ค.
์๋์ ๊ฐ์ด ์์ฒญ์ ํ์๋ฉด ๋๊ฒ ์ต๋๋ค.
Request :
@GetMapping("/naver")
public String naverOAuthRedirect(@RequestParam String code, @RequestParam String state, Model model) {
... ์๋ต ....
// ์ด์ ์ ๋ฐ์๋ Access Token ์๋ต
ObjectMapper objectMapper = new ObjectMapper();
// json -> ๊ฐ์ฒด๋ก ๋งคํํ๊ธฐ ์ํด NaverOauthParams ํด๋์ค ์์ฑ
NaverOauthParams naverOauthParams = null;
try {
naverOauthParams = objectMapper.readValue(accessTokenResponse.getBody(), NaverOauthParams.class);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
// header๋ฅผ ์์ฑํด์ access token์ ๋ฃ์ด์ค๋๋ค.
HttpHeaders profileRequestHeader = new HttpHeaders();
profileRequestHeader.add("Authorization", "Bearer " + naverOauthParams.getAccess_token());
HttpEntity<HttpHeaders> profileHttpEntity = new HttpEntity<>(profileRequestHeader);
// profile api๋ก ์์ฑํด๋ ํค๋๋ฅผ ๋ด์์ ์์ฒญ์ ๋ณด๋
๋๋ค.
ResponseEntity<String> profileResponse = rt.exchange(
"https://openapi.naver.com/v1/nid/me",
HttpMethod.POST,
profileHttpEntity,
String.class
);
return "profile response : " + profileResponse.getBody();
}
Response :
์์ฒญํ ์ ๋ณด์ ๋ฐ๋ผ์ ์๋์ ๊ฐ์ด ๊ฐ์ด ์๋ต ๋ฐ์ดํฐ๋ก ๋ฐ์ ์ ์๊ฒ ์ต๋๋ค.
์ด์ ๋ค์ด๋ฒ ๋ก๊ทธ์ธ์ ๋ํด์ ์์๋ณด์์ต๋๋ค.
๊ฐ์ฌํฉ๋๋ค!
REFERENCES