2024. 2. 7. 09:41ใSpring/[2024] Spring Boot
์์ฆ์ ์นด์นด์ค, ๋ค์ด๋ฒ๋ฅผ ์ด์ฉํ Login Api ๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค.
์ค์ ์ฌ์ฉํ๊ธฐ ์ ์ ์ํ ํ๋ก์ ํธ๋ฅผ ๋ง๋ค์ด kakao login api ๋์ ๋ฐฉ์์ ์์๋ณผ ๊ฒ์ด๋ค.
REST API๋ฅผ ์ฌ์ฉํ ์นด์นด์ค ๋ก๊ทธ์ธ์ PC ๋ฐ ๋ชจ๋ฐ์ผ ์น์์ ์ ํฉํ ๋ฐฉ์์ด๋ค.
์นด์นด์ค ๋ก๊ทธ์ธ์ OAuth 2.0 ๊ธฐ๋ฐ์ ์์ ๋ก๊ทธ์ธ ์๋น์ค๋ก ์นด์นด์ค ๋ก๊ทธ์ธ์ ์ด์ฉํ๋ฉด ์ฌ์ฉ์๊ฐ ์นด์นด์คํก ๋๋ ์นด์นด์ค ๊ณ์ ์ผ๋ก ์์ฝ๊ฒ ์๋น์ค์ ๋ก๊ทธ์ธ ํ ์ ์๋ค.
์นด์นด์ค ๋ก๊ทธ์ธ ์๋น์ค ๊ณผ์
1๏ธโฃ ์นด์นด์ค ๋ก๊ทธ์ธ
- ์ฌ์ฉ์๊ฐ ์๋น์ค์์ ์นด์นด์ค ๋ก๊ทธ์ธ ๋ฒํผ์ ํด๋ฆญํฉ๋๋ค. ์๋น์ค๋ ์นด์นด์ค ์ธ์ฆ ์๋ฒ๋ก ์ธ๊ฐ ์ฝ๋ ๋ฐ๊ธ์ ์์ฒญํฉ๋๋ค.
- ์นด์นด์ค ์ธ์ฆ ์๋ฒ๋ ์ฌ์ฉ์์๊ฒ ์ธ์ฆ์ ์์ฒญํฉ๋๋ค. (์ฐธ๊ณ : ์ฌ์ฉ์ ํ๊ฒฝ์ ๋ฐ๋ฅธ ์ธ์ฆ ๋ฐฉ๋ฒ)
- ์นด์นด์คํก์ผ๋ก ๋ก๊ทธ์ธ: ์นด์นด์คํก ์คํ, ์นด์นด์คํก์ ์ฐ๊ฒฐ๋ ์นด์นด์ค๊ณ์ ์ ์๊ฒฉ์ ๋ณด(Credentials)๋ก ์ฌ์ฉ์ ์ธ์ฆ
- ์นด์นด์ค๊ณ์ ์ผ๋ก ๋ก๊ทธ์ธ: ๊ณ์ ์ ๋ณด๋ฅผ ์ ๋ ฅํด ๋ก๊ทธ์ธํ๋ ํ๋ฉด ์ถ๋ ฅ, ํด๋น ์นด์นด์ค๊ณ์ ์ ์๊ฒฉ์ ๋ณด๋ก ์ฌ์ฉ์ ์ธ์ฆ
- ์นด์นด์ค ์ธ์ฆ ์๋ฒ๋ ์ฌ์ฉ์ ์ธ์ฆ ์ฑ๊ณต ์, ์๋น์ค ์ฑ์ ๋์ํญ๋ชฉ ์ค์ ์ ๋ฐํ์ผ๋ก ์ฌ์ฉ์์๊ฒ ๋์ ํ๋ฉด์ ์ถ๋ ฅํฉ๋๋ค.
- ์ฌ์ฉ์๊ฐ ํ์ ๋์ํญ๋ชฉ์ ๋์ํ๊ณ ๋ก๊ทธ์ธ์ ์์ฒญํ๋ฉด, ์นด์นด์ค ์ธ์ฆ ์๋ฒ๋ ์ธ๊ฐ ์ฝ๋(Authorization Code)๋ฅผ ๋ฐ๊ธํด ์๋น์ค ์ฑ์ ๋ฑ๋ก๋ Redirect URI๋ก ์ ๋ฌํฉ๋๋ค.
- ์๋น์ค๋ ์ ๋ฌ๋ฐ์ ์ธ๊ฐ ์ฝ๋๋ก ํ ํฐ์ ์์ฒญํ์ฌ ๋ฐ์ต๋๋ค.
2๏ธโฃ ํ์ ํ์ธ ๋ฐ ๊ฐ์
- ์๋น์ค๋ ์นด์นด์ค ๋ก๊ทธ์ธ์ ์๋ฃํ์ฌ ๋ฐ๊ธ๋ฐ์ ํ ํฐ์ผ๋ก ์ฌ์ฉ์ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ๋ฅผ ์์ฒญํฉ๋๋ค.
- OpenID Connect ์ฌ์ฉ ์: OIDC: ์ฌ์ฉ์ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ API๋ก ๋์ฒด ๊ฐ๋ฅ
- ์นด์นด์ค API ์๋ฒ๋ ์์ฒญ ์ ์ฌ์ฉ๋ ํ ํฐ์ ์ ํจ์ฑ์ ๊ฒ์ฆํ๊ณ , ์์ฒญ์ ์ฒ๋ฆฌํ๊ณ ์๋น์ค์ ์๋ตํฉ๋๋ค.
- ์๋น์ค ์๋ฒ๋ ์นด์นด์ค๋ก๋ถํฐ ์ ๊ณต๋ฐ์ ์ฌ์ฉ์ ์ ๋ณด๋ก ํด๋น ์ฌ์ฉ์๊ฐ ์๋น์ค์ ํ์ ๊ฐ์
๋์ด ์๋์ง ํ์ธํฉ๋๋ค.
- ์ด๋ฏธ ํ์ ๊ฐ์ ๋ ์ฌ์ฉ์: Step 3์ ์๋น์ค ๋ก๊ทธ์ธ ๋จ๊ณ ์ํ
- ์์ง ํ์ ๊ฐ์ ๋์ง ์์ ์ฌ์ฉ์: ์นด์นด์ค์์ ์ ๊ณต๋ฐ์ ์ฌ์ฉ์ ์ ๋ณด๋ก ์๋น์ค ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ํ์ ๊ฐ์ ์ฒ๋ฆฌ
-> ์นด์นด์ค๊ฐ ๋ฐ์ดํฐ์ ์ ๊ทผํ๋ ๊ฒ์ ์๋๊ธฐ ๋๋ฌธ์ ํ์ ์ ๋ณด๋ฅผ ๋์ ์ ์ฅํ๊ฑฐ๋ ์ญ์ ํ์ง ์๊ธฐ ๋๋ฌธ์ ์ด๋ ํ์ ์ ๋ณด ์ฒ๋ฆฌ๋ ์๋น์ค์์ ์์ฒด ๊ตฌํํด์ผ ํ๋ค.
3๏ธโฃ ์๋น์ค ๋ก๊ทธ์ธ
- ์๋น์ค ์๋ฒ๋ ์๋น์ค ํด๋ผ์ด์ธํธ์ ํด๋น ์ฌ์ฉ์์ ๋ก๊ทธ์ธ์ ๋ํ ์ธ์
์ ๋ฐ๊ธํฉ๋๋ค.
- OpenID Connect ์ฌ์ฉ ์: ํ ํฐ๊ณผ ํจ๊ป ๋ฐ๊ธ๋ ID ํ ํฐ์ผ๋ก ์๋น์ค ๋ก๊ทธ์ธ ์ธ์ ์ ๋์ ํ ์ ์์
- ์๋น์ค ํด๋ผ์ด์ธํธ๋ ์๋น์ค ์ธ์ ์ ์ ๋ฌ๋ฐ์ ๋ก๊ทธ์ธ ์๋ฃ ์ฒ๋ฆฌํ๊ณ , ์ฌ์ฉ์๋ฅผ ๋ก๊ทธ์ธ๋ ์๋น์ค ํ๋ฉด์ผ๋ก ์ด๋์ํต๋๋ค.
์นด์นด์ค ๋ก๊ทธ์ธ ์๋น์ค ์ฌ์ ์ค์
Kakao Developers
์นด์นด์ค API๋ฅผ ํ์ฉํ์ฌ ๋ค์ํ ์ดํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐํด๋ณด์ธ์. ์นด์นด์ค ๋ก๊ทธ์ธ, ๋ฉ์์ง ๋ณด๋ด๊ธฐ, ์น๊ตฌ API, ์ธ๊ณต์ง๋ฅ API ๋ฑ์ ์ ๊ณตํฉ๋๋ค.
developers.kakao.com
-> ๋จผ์ ์นด์นด์ค ๊ฐ๋ฐ์ ์ฌ์ดํธ์ ๊ฐ์ ๋ก๊ทธ์ธ ํ ๋ด๊ฐ ๊ฐ๋ฐํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฑ๋กํด์ค์ผ ํ๋ค.
1๏ธโฃ ์ ํ๋ฆฌ์ผ์ด์ ์ถ๊ฐํ๊ธฐ
์ฌ๊ธฐ์ ๊ฐ์ ๋ก๊ทธ์ธ ์๋น์ค๋ฅผ ํ ์ฑ ์ด๋ฆ, ์ฌ์ ์๋ช , ์นดํ ๊ณ ๋ฆฌ ๋ฑ์ ์์ฑํด์ค๋ค.
๋๋ ํ ์คํธํ ์ฉ๋์ด๊ธฐ ๋๋ฌธ์ ์์ธํ ์ ์ง๋ ์์๋ค..!
2๏ธโฃ ์ ํ๋ฆฌ์ผ์ด์ ์ถ๊ฐ ํ Rest API ํค ํ์ธํ๊ธฐ
์ ํ๋ฆฌ์ผ์ด์ ์ถ๊ฐ ํ [์์ฝ ์ ๋ณด] ํ์ด์ง๋ฅผ ํ์ธํ๋ฉด REST API ์ฑ ํค๋ฅผ ํ์ธํ ์ ์๋ค.
3๏ธโฃ Web ํ๋ซํผ ๋ฑ๋กํ๊ธฐ
-> [ํ๋ซํผ] ํ์ด์ง์ Web ํ๋ซํผ ๋ฑ๋ก์ ํด๋ฆญํ๋ฉด
์ด๋ ๊ฒ ๋๋ฉ์ธ ๋ฑ๋กํ๋ ํ์ ์ด ๋์จ๋ค.
๋๋ ํ ์คํธํ๋ ํ๋ก์ ํธ์ด๊ธฐ ๋๋ฌธ์ http://localhost:8080 ์ผ๋ก ๋ฑ๋กํ๋ค. ใ ใ
๊ทธ ๋ค์ ์นด์นด์ค ๋ก๊ทธ์ธ ์ฌ์ฉ ์ ์ฝ๋ฐฑ ๋ฐ์ Redirect URI ๋ฅผ ๋ฑ๋กํด์ผ ํ๋ค.
-> ๊ทธ ์ ์ [์นด์นด์ค ๋ก๊ทธ์ธ] ํ์ด์ง์์ ์นด์นด์ค ๋ก๊ทธ์ธ ํ์ฑํ๋ฅผ on ํด์ฃผ๊ณ , Redirect URI๋ฅผ ๋ฑ๋กํด์ค๋ค.
์ฌ๊ธฐ์๋ ๊ฐ์ ๊ฐ๋ฐํ Redirect URI๋ฅผ ์์ฑํด์ฃผ๋ฉด ๋๋ค.
๋๋ http://localhost:8080/login/kakao/code ๋ก ๋ฑ๋กํด์คฌ๋ค.
4๏ธโฃ ๋์ ํญ๋ชฉ ์ค์
-> ์๋ง ๋น์ฆ์ฑ ์ ์ฒญ์ํ๋ฉด ๋ค๋ฅธ ์ ๋ณด๋ค์ ๊ถํ์ด ์์ด์ ๋๋ค์, ํ๋กํ ์ฌ์ง๋ง ํ์๋ก ๋ฐ์ ์ ์๋ค.
* ์ถ๊ฐ๋ก ์นด์นด์ค ๋ก๊ทธ์ธ ์ด๋ฏธ์ง ๋ฒํผ ๋ค์ด๋ฐ๊ธฐ
์ด๋ ๊ฒ ๋ก๊ทธ์ธ ์ด๋ฏธ์ง ๋ฒํผ์ ๋ค์ด ๋ฐ์ ์ ์๋ค.
-> ๋ก๊ทธ์ธ ์ด๋ฏธ์ง ๋ฒํผ๊น์ง ๋ฐ์๋ค๋ฉด kakao Devleopers์์ ์ค์ ํ ๊ฑด ๋๋ฌ๋ค.
* ์นด์นด์ค ๋ก๊ทธ์ธ REST API ๋ฌธ์
https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api
Kakao Developers
์นด์นด์ค API๋ฅผ ํ์ฉํ์ฌ ๋ค์ํ ์ดํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐํด๋ณด์ธ์. ์นด์นด์ค ๋ก๊ทธ์ธ, ๋ฉ์์ง ๋ณด๋ด๊ธฐ, ์น๊ตฌ API, ์ธ๊ณต์ง๋ฅ API ๋ฑ์ ์ ๊ณตํฉ๋๋ค.
developers.kakao.com
์นด์นด์ค ๋ก๊ทธ์ธ ์ํ ํ๋ก์ ํธ ๋ง๋ค๊ธฐ
์นด์นด์ค ๋ก๊ทธ์ธ ๊ณผ์ โ
1. ์ธ๊ฐ ์ฝ๋ ๋ฐ๊ธฐ
2. ํ ํฐ ๋ฐ๊ธฐ
3. ํ ํฐ์ผ๋ก ์ฌ์ฉ์ ์ ๋ณด ์ป๊ธฐ
1๏ธโฃ ์ธ๊ฐ ์ฝ๋ ๋ฐ๊ธฐ
์ฌ์ฉ์๊ฐ ๋ก๊ทธ์ธ ๋ฒํผ์ ํด๋ฆญํ๋ฉด https://kauth.kakao.com/oauth/authorize ์ด URL๋ก ์ธ๊ฐ ์ฝ๋๋ฅผ ์์ฒญํ๋ค.
๊ทธ๋ฌ๋ฉด ์นด์นด์ค ์ธ์ฆ ์๋ฒ๋ ์นด์นด์ค ๋ก๊ทธ์ธ ๋์ ํ๋ฉด์ ํธ์ถํ๊ณ , ์ฌ์ฉ์ ๋์๋ฅผ ๊ฑฐ์ณ ์ธ๊ฐ ์ฝ๋๋ฅผ ๋ฐ๊ธํ๋ค.
์ด๋ ๋์ ํ๋ฉด์ ์์์ ์ค์ ํ ๋์ ํญ๋ชฉ์ ๋ํด ์ฌ์ฉ์์๊ฒ ์ธ๊ฐ(๋์)๋ฅผ ๊ตฌํ๋ค.
์ธ๊ฐ ์ฝ๋๋ ๋์ ํ๋ฉด์ ํตํด ์ธ๊ฐ๋ฐ์ ๋์ํญ๋ชฉ ์ ๋ณด๋ฅผ ๊ฐ๊ณ ์๊ณ , ์ธ๊ฐ ์ฝ๋๋ฅผ ์ฌ์ฉํด ํ ํฐ ๋ฐ๊ธฐ๋ฅผ ์์ฒญํ ์ ์๋ค.
โ ๊ทธ๋ฆฌ๊ณ ์ด๋ ๋์ํ๋ฉด์ ์ฌ์ฉ์์ ์ฑ์ด ์ฒ์ ์ฐ๊ฒฐ๋ ๋๋ง ๋ํ๋๋ค!
์ฌ์ฉ์๊ฐ ์ด๋ฏธ ๋์ ํ๋ฉด์์ ์๋น์ค ์ด์ฉ์ ํ์ํ ๋์ํญ๋ชฉ์ ๋์ ์๋ฃํ ๊ฒฝ์ฐ, ํด๋น ์ฌ์ฉ์์ ์นด์นด์ค ๋ก๊ทธ์ธ ์์๋ ๋์ ํ๋ฉด์ด ๋ํ๋์ง ์๊ณ ์ฆ์ ์ธ๊ฐ ์ฝ๋๊ฐ ๋ฐ๊ธ๋ฉ๋๋ค. ์ฌ์ฉ์์ ์ฑ์ด ์ฐ๊ฒฐ๋ ์ดํ ๋ค์ ๋์ ํ๋ฉด์ ํตํด ํน์ ๋์ํญ๋ชฉ์ ๋ํ ์ฌ์ฉ์ ๋์๋ฅผ ์์ฒญํ๋ ค๋ฉด ์ถ๊ฐ ํญ๋ชฉ ๋์ ๋ฐ๊ธฐ๋ก ๋์ ํ๋ฉด์ ํธ์ถํ ์ ์์ต๋๋ค. ์๋น์ค ๊ฐ์
๊ณผ์ ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์๋ฃ๋์ง ์์ ๋ค์ ๋์ ํ๋ฉด์ ํธ์ถํด์ผ ํ ๊ฒฝ์ฐ์๋ ์ฐ๊ฒฐ ๋๊ธฐ ํ ๋ค์ ์ธ๊ฐ ์ฝ๋ ๋ฐ๊ธฐ๋ฅผ ์์ฒญํฉ๋๋ค.
์ฌ๊ธฐ์ ์ด์ ์ฌ์ฉ์๊ฐ ๋ชจ๋ ํ์ ๋์ํญ๋ชฉ์ ๋์ํ๊ณ [๋์ํ๊ณ ๊ณ์ํ๊ธฐ] ๋ฒํผ์ ๋๋ฅด๋ฉด
-> redirect_uri๋ก ์ธ๊ฐ ์ฝ๋๋ฅผ ๋ด์ ์ฟผ๋ฆฌ ์คํธ๋ง ์ ๋ฌํ๊ณ ,
[์ทจ์] ๋ฒํผ์ ๋๋ฌ ๋ก๊ทธ์ธ ์ทจ์ํ๋ฉด
-> redirect_uri๋ก ์๋ฌ ์ ๋ณด๋ฅผ ๋ด์ ์ฟผ๋ฆฌ ์คํธ๋ง ์ ๋ฌํ๋ค.
์์ฒญ ์ฟผ๋ฆฌํ๋ผ๋ฏธํฐ๋ ๋ฐ์ url์์ ํ์ธํ ์ ์๋ค.
https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#request-code-request-query
Kakao Developers
์นด์นด์ค API๋ฅผ ํ์ฉํ์ฌ ๋ค์ํ ์ดํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐํด๋ณด์ธ์. ์นด์นด์ค ๋ก๊ทธ์ธ, ๋ฉ์์ง ๋ณด๋ด๊ธฐ, ์น๊ตฌ API, ์ธ๊ณต์ง๋ฅ API ๋ฑ์ ์ ๊ณตํฉ๋๋ค.
developers.kakao.com
-> ๊ทธ ์ค ํ์๋ client_id, redirect_uri, response_type ์ด๋ ๊ฒ 3๊ฐ์ง ์ด๋ค.
application-private.yml
kakao:
api_key:
redirect_uri:
-> application-private.yml์ ์นด์นด์ค ๊ฐ๋ฐ์ ์ฌ์ดํธ์์ ์ ํ๋ฆฌ์ผ์ด์ ๋ฑ๋ก ํ ๋ฐ์ REST API ์ฑ ํค์ ์ค์ ํ Redirect_uri๋ฅผ ๋ด์์ ๋ฐ๋ก ๊ด๋ฆฌํด์ค๋ค.
application.yml
spring:
profiles:
include: private
-> ๊ทธ๋ฆฌ๊ณ application.yml์ private yml์ ํฌํจํ๋๋ก ํ๋ค.
KakaoApi
@Slf4j
@Getter
@Component
public class KaKaoApi
{
@Value("${kakao.api_key}")
private String kakaoApiKey;
@Value("${kakao.redirect_uri}")
private String kakaoRedirectUri;
}
-> application-private.yml์ ๊ฐ์ ๋ด๋ vo๋ฅผ ๋ง๋ค์ด์ค๋ค.
TestController
@GetMapping("/login")
public String loginForm(Model model)
{
model.addAttribute("kakaoApiKey", kaKaoApi.getKakaoApiKey());
model.addAttribute("kakaoRedirectUri", kaKaoApi.getKakaoRedirectUri());
return "login";
}
-> kakaoApi ๋ฅผ ์๋ ์ฃผ์ ๋ฐ์์ kakaoApikey์ kakaoRedirectUri๋ฅผ login ํ์ด์ง์ ๋ด์ ๋๊ธด๋ค.
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Kakao & Naver Login API TEST</title>
</head>
<body>
<div class="text-center">
<a href="https://kauth.kakao.com/oauth/authorize"
th:href="@{https://kauth.kakao.com/oauth/authorize(client_id=${kakaoApiKey}, redirect_uri=${kakaoRedirectUri}, response_type='code')}">
<img src="/images/kakao_login_medium_narrow.png">
</a>
</div>
</body>
</html>
-> ๋งจ ์ฒ์ ๋ก๊ทธ์ธ ํ์ด์ง์ด๋ค. ์ด ๋ฒํผ์ ํด๋ฆญํ๋ฉด https://kauth.kakao.com/oauth/authorize ์ด url๋ก client_id, redierct_uri, response_type ๊ฐ์ ๋ด์์ ์์ฒญํ๋ค. ์ด๋ response_type ์๋ code๋ก ๊ณ ์ ํด์ ๋ณด๋ธ๋ค.
-> ๊ทธ๋ฌ๋ฉด ์๋ต๊ฐ์ผ๋ก ํ ํฐ ๋ฐ๊ธฐ ์์ฒญ์ ํ์ํ code๋ฅผ redirect_uri์ ๋ด์ ์ ๋ฌํ๋ค.
2๏ธโฃ ํ ํฐ ๋ฐ๊ธฐ
์ด์ ๋ฐ์ ์ธ๊ฐ ์ฝ๋๋ก ํ ํฐ ๋ฐ๊ธ์ ์์ฒญํด์ผ ํ๋ค. ์ธ๊ฐ ์ฝ๋ ๋ฐ๊ธฐ๋ง์ผ๋ก๋ ์นด์นด์ค ๋ก๊ทธ์ธ์ด ์๋ฃ๋์ง ์๋๋ค. ํ ํฐ ๋ฐ๊ธฐ ๊น์ง ๋ง์ณ์ผ ๋ก๊ทธ์ธ์ ์ ์์ ์ผ๋ก ์ํํ ์ ์๋ค.
ํ์ ํ๋ผ๋ฏธํฐ๋ฅผ ํฌํจํด์ https://kauth.kakao.com/oauth/token ์ POST๋ก ์์ฒญํ๋ค.
์์ฒญ ์ฑ๊ณต์ ์๋ต์ ํ ํฐ๊ณผ ํ ํฐ ์ ๋ณด๋ฅผ ํฌํจํด์ ๋ฐํํ๋ค.
๊ทธ๋ฆฌ๊ณ ์ด ๋ฐ์ ์ก์ธ์ค ํ ํฐ์ผ๋ก ์ฌ์ฉ์ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ API ๋ฅผ ํธ์ถํด ํ์ํ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๋ฐ์ ์๋น์ค ํ์ ๊ฐ์ ๋ฐ ๋ก๊ทธ์ธ์ ์๋ฃํด์ผ ํ๋ค.
KakaoApi
public String getAccessToken(String code)
{
String reqUrl = "https://kauth.kakao.com/oauth/token";
RestTemplate restTemplate = new RestTemplate();
// HttpHeader Object
HttpHeaders headers = new HttpHeaders();
headers.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");
// HttpBody Object
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("grant_type", "authorization_code");
params.add("client_id", kakaoApiKey);
params.add("redirect_uri", kakaoRedirectUri);
params.add("code", code);
// http ๋ฐ๋ params ์ http ํค๋ headers ๋ฅผ ๊ฐ์ง ์ํฐํฐ
HttpEntity<MultiValueMap<String, String>> kakaoTokenRequest = new HttpEntity<>(params, headers);
// reqUrl ๋ก Http ์์ฒญ, POST ๋ฐฉ์
ResponseEntity<String> response = restTemplate.exchange(reqUrl,
HttpMethod.POST,
kakaoTokenRequest,
String.class);
String responseBody = response.getBody();
JsonObject asJsonObject = JsonParser.parseString(responseBody).getAsJsonObject();
return asJsonObject.get("access_token").getAsString();
}
-> https://kauth.kakao.com/oauth/token ์ ๋ฐ์ grant_type์ authorization_code๋ก ๊ณ ์ ํ๊ณ , client_id, redirect_uri, code ๋ฅผ ๋ด์ post๋ก ์์ฒญํ๋ค.
์ด๋ ๋ฐ๋์ Content-type์ application/x-www-form-urlencoded;charset=utf-8 ๋ก ๋ณด๋ด์ผํ๋ค!!!! ์๋๋ฉด ์๋ฌ๋จ ใ ใ
์ด๋ ๊ฒ ์์ฒญํ๋ฉด ์๋ต์ผ๋ก
์ฌ์ฉ์ ์์ธ์ค ํ ํฐ ๊ฐ์ ์ ๋ฌ๋ฐ๋๋ค.
3๏ธโฃ ์ฌ์ฉ์ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ
์ด ์์ธ์ค ํ ํฐ ๊ฐ์ ๊ฐ์ง๊ณ ํ์ฌ ๋ก๊ทธ์ธํ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์์ ์ด ์ฌ์ฉ์๊ฐ ์ฐ๋ฆฌ ์๋น์ค ๊ฐ์ ํ ํ์์ธ์ง, ์๋์ง ๋น๊ต ํ ์๋ ์ฌ์ฉ์๋ฉด ํ์ ๊ฐ์ ์ ์งํํ๊ณ , ์๋ ์ฌ์ฉ์๋ฉด ์ ๋ณด ๋น๊ต ํ ๋ก๊ทธ์ธ ์ฒ๋ฆฌ๋ฅผ ์๋ฃํ๋ฉด ๋๋ค.
KakaoApi
public KakaoProfile getUserInfo(String accessToken) {
String reqUrl = "https://kapi.kakao.com/v2/user/me";
RestTemplate restTemplate = new RestTemplate();
//HttpHeader ์ค๋ธ์ ํธ
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Bearer " + accessToken);
headers.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");
//http ํค๋(headers)๋ฅผ ๊ฐ์ง ์ํฐํฐ
HttpEntity<MultiValueMap<String, String>> kakaoProfileRequest = new HttpEntity<>(headers);
//reqUrl๋ก Http ์์ฒญ , POST ๋ฐฉ์
ResponseEntity<String> response = restTemplate.exchange(reqUrl, HttpMethod.POST, kakaoProfileRequest, String.class);
KakaoProfile kakaoProfile = new KakaoProfile(response.getBody());
return kakaoProfile;
}
-> https://kapi.kakao.com/v2/user/me ๋ก ์ฌ์ฉ์ ์์ธ์ค ํ ํฐ์ Authorization์ ๋ด์์ POST ๋ก ์์ฒญํ๋ค.
์์ฒญ์ ์ฑ๊ณตํ๋ฉด ์ด์ ์๋ต์ ์ด์ ์นด์นด์ค ๊ณ์ ์ ๋ณด๋ฅผ ๋ด์์ค๋ค.
*kakao_account์ ๋ํ ์ ๋ณด
https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#kakaoaccount
Kakao Developers
์นด์นด์ค API๋ฅผ ํ์ฉํ์ฌ ๋ค์ํ ์ดํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐํด๋ณด์ธ์. ์นด์นด์ค ๋ก๊ทธ์ธ, ๋ฉ์์ง ๋ณด๋ด๊ธฐ, ์น๊ตฌ API, ์ธ๊ณต์ง๋ฅ API ๋ฑ์ ์ ๊ณตํฉ๋๋ค.
developers.kakao.com
KakaoProfile
@Getter
public class KakaoProfile {
private Integer id;
private LocalDateTime connectedAt;
private String nickname;
public KakaoProfile(String jsonResponseBody){
JsonParser parser = new JsonParser();
JsonElement element = parser.parse(jsonResponseBody);
this.id = element.getAsJsonObject().get("id").getAsInt();
String connected_at = element.getAsJsonObject().get("connected_at").getAsString();
connected_at = connected_at.substring(0, connected_at.length() - 1);
LocalDateTime connectDateTime = LocalDateTime.parse(connected_at, DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"));
this.connectedAt = connectDateTime;
JsonObject properties = element.getAsJsonObject().get("properties").getAsJsonObject();
this.nickname = properties.getAsJsonObject().get("nickname").getAsString();
}
}
๋ฐ์ response body๋ฅผ KakaoProfile ์ด๋ผ๋ vo๋ฅผ ํ๋ ๋ง๋ค์ด์ ํ์ ๋ฒํธ, ์๋น์ค์ ์ฐ๊ฒฐ๋ ์๊ฐ, ๋๋ค์ ๋ฑ์ ์ ๋ณด๋ฅผ ๋ฃ์ด์คฌ๋ค.
TestController
@ResponseBody
@GetMapping("/login/kakao/code")
public Map<String, Object> kakaoLogin(@RequestParam String code)
{
Map<String, Object> map = new HashMap<>();
// 1. ์ธ๊ฐ ์ฝ๋ ๋ฐ๊ธฐ -> @RequestParam String code
// 2. ํ ํฐ ๋ฐ๊ธฐ
String accessToken = String.valueOf(kaKaoApi.getAccessToken(code));
// 3. ์ฌ์ฉ์ ์ ๋ณด ๋ฐ๊ธฐ
KakaoProfile userInfo = kaKaoApi.getUserInfo(accessToken);
map.put("nickName", userInfo.getNickname());
map.put("accessToken", accessToken);
System.out.println("userInfo.getNickname() = " + userInfo.getNickname());
System.out.println("accessToken = " + accessToken);
return map;
}
-> ์ฌ์ฉ์๊ฐ ๋ก๊ทธ์ธํ ๋ฒํผ์ ๋๋ ์ ๋ ๋์ํ๋ ์ฝ๋์ด๋ค. (๋ก๊ทธ์ธ ํ ๋ค๋ฅธ ์ฒ๋ฆฌ๋ฅผ ํ์ง ์๊ณ ์๊ธฐ ๋๋ฌธ์ ๊ทธ๋ฅ ์ ๋ณด๋ฅผ MAP์ ๋ด์ ๋ฆฌํดํด ๋ง๋ฌด๋ฆฌํ๋ค.)
์ฌ๊ธฐ๊น์ง๊ฐ ์นด์นด์ค ๋ก๊ทธ์ธ API๋ฅผ ์ฌ์ฉํ๋ ์์ ์ด๊ณ , ๊ทธ ๋ค์ ๊ฐ์์ ์๋น์ค์ ํ์ ๊ฐ์ ๋ฐ ๋ก๊ทธ์ธ ์ฒ๋ฆฌ ์๋ฃ๋ ์ง์ ๊ตฌํํด์ผํ๋ค!
๋๋ ์ฐ์ ์ฌ๊ธฐ๊น์ง๋ง ๊ตฌํํ๊ณ , ๋์ค์ ์ํ๋ฆฌํฐ๋ฅผ ์ฌ์ฉํด์ ๋ ๋ฐ์ ์์ผ๋ณผ ์์ ์ด๋ค.!