๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Spring

REST-API ํ™œ์šฉํ•œ ์นด์นด์˜ค ์†Œ์…œ ๋กœ๊ทธ์ธ ๊ตฌํ˜„(feat. React, SpringBoot)

by JulesJ 2022. 8. 21.
728x90

REST-API ํ™œ์šฉํ•œ ์นด์นด์˜ค ์†Œ์…œ ๋กœ๊ทธ์ธ ๊ตฌํ˜„(feat. React, SpringBoot)

 

 

REST-API๋ฅผ ํ™œ์šฉํ•œ ์นด์นด์˜ค ๋กœ๊ทธ์ธ ๋ฌธ์„œ

https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api

 

Kakao Developers

์นด์นด์˜ค API๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋‹ค์–‘ํ•œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•ด๋ณด์„ธ์š”. ์นด์นด์˜ค ๋กœ๊ทธ์ธ, ๋ฉ”์‹œ์ง€ ๋ณด๋‚ด๊ธฐ, ์นœ๊ตฌ API, ์ธ๊ณต์ง€๋Šฅ API ๋“ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

developers.kakao.com

 

์นด์นด์˜ค ๊ฐœ๋ฐœ์ž ํŽ˜์ด์ง€

https://developers.kakao.com/

 

Kakao Developers

์นด์นด์˜ค API๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋‹ค์–‘ํ•œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•ด๋ณด์„ธ์š”. ์นด์นด์˜ค ๋กœ๊ทธ์ธ, ๋ฉ”์‹œ์ง€ ๋ณด๋‚ด๊ธฐ, ์นœ๊ตฌ API, ์ธ๊ณต์ง€๋Šฅ API ๋“ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

developers.kakao.com

 

 

๐Ÿ’ก ๊ฐ„๋‹จ ์š”์•ฝ

- REST-API๋ฅผ ํ™œ์šฉํ•œ ์นด์นด์˜ค ๋กœ๊ทธ์ธ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜์˜€๋‹ค.
- ๊ฐœ๋ฐœํ™˜๊ฒฝ : React + SpringBoot
- ํ”„๋ก ํŠธ์—”๋“œ : ์นด์นด์˜ค๋กœ๋ถ€ํ„ฐ ์ธ๊ฐ€์ฝ”๋“œ๋ฅผ ๋ฐ›๊ณ  ๋ฐ›์€ ์ธ๊ฐ€์ฝ”๋“œ๋ฅผ ๋ฐฑ์—”๋“œ์— ๋„˜๊ฒจ์ฃผ๋Š” ์—ญํ• ์„ ํ•˜์˜€๋‹ค. (+ ๋งˆ์ง€๋ง‰ ๋ฆฌ๋‹ค์ด๋ ‰ํŒ…๊นŒ์ง€)
- ์ธ๊ฐ€์ฝ”๋“œ๋ฅผ ๋„˜๊ธฐ๋ฉด ๋ฐฑ์—”๋“œ๋กœ๋ถ€ํ„ฐ (์šฐ๋ฆฌ ์‚ฌ์ดํŠธ ์ „์šฉ) JWT๋ฅผ ๋ฐœ๊ธ‰๋ฐ›์•˜๋‹ค.
- ๋ฐฑ์—”๋“œ : ํ”„๋ก ํŠธ๋กœ๋ถ€ํ„ฐ ์ธ๊ฐ€ ์ฝ”๋“œ๋ฅผ ๋„˜๊ฒจ๋ฐ›๊ณ  ์นด์นด์˜ค๋กœ๋ถ€ํ„ฐ ํ† ํฐ์„ ๋ฐœ๊ธ‰๋ฐ›๋Š”๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํ•ด๋‹น ํ† ํฐ์— ๋‹ด๊ธด ์œ ์ € ์ •๋ณด๋ฅผ ํ™œ์šฉํ•ด JWT๋ฅผ ์ƒˆ๋กญ๊ฒŒ ๋ฐœ๊ธ‰ ํ›„ ํ”„๋ก ํŠธ์—๊ฒŒ ๋Œ๋ ค์ค€๋‹ค.

 

 

โ— ์นด์นด์˜ค ํ† ํฐ์„ ๊ทธ๋Œ€๋กœ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ง์ ‘ ๋„˜๊ฒจ์ฃผ๊ณ  ์‚ฌ์šฉ์‹œํ‚ค๋ฉด ๊ณ ์†Œ๋‹นํ•  ์ˆ˜๋„ ์žˆ๋‹ค?!
-> ํ”„๋ŸฐํŠธ์—”๋“œ์—์„œ๋Š” ๊ฑฐ์˜ ๋‹ค (url+http์ •๋ณด) ์กฐํšŒ๊ฐ€ ๊ฐ€๋Šฅํ•ด์„œ ํ•ดํ‚น๋‹นํ•˜๋ฉด ์‚ฌ์šฉ์ž์˜ ์นด์นด์˜ค ์ •๋ณด๊ฐ€ ์œ ์ถœ๋  ์ˆ˜๋„ ์žˆ์œผ๋‹ˆ ํ™•์‹คํžˆ ๊ณ ์†Œ๋‹นํ•  ์ˆ˜๋„ ์žˆ๋‹ค๊ณ  ์ฐธ๊ณ ํ•œ ์‚ฌ์ดํŠธ ๊ฐœ๋ฐœ์ž๋ถ„์ด ์–ธ๊ธ‰ํ•˜์‹ฌ..?
→ Next.js์˜ SSR์„ ์ด์šฉํ•ด์„œ ์•ˆ๋ณด์ด๊ฒŒ ํ•  ์ˆ˜๋Š” ์žˆ์„ ์ˆ˜๋„ ์žˆ๋‹ค๋Š” ํ”„๋ŸฐํŠธ ๊ฐœ๋ฐœ์ž๋ง์„ ๋“ฃ๊ธฐ๋Š” ๋“ค์—ˆ๋‹ค (๊ณต๋ถ€ํ•ด๋ด์•ผ ๊ฒ ๋‹ค..)

 

 

์†Œ์…œ ๋กœ๊ทธ์ธ ๊ณผ์ •

๊ฐ„๋‹จํ•œ ์†Œ์…œ ๋กœ๊ทธ์ธ ์ง„ํ–‰์‚ฌํ•ญ์˜ ํ๋ฆ„์„ ๋‹ด์€ ์ด๋ฏธ์ง€

 

 

์ธ๊ฐ€ ์ฝ”๋“œ ๋ฐ›๊ธฐ-์นด์นด์˜ค ๊ฐœ๋ฐœ์ž ๊ธฐ๋ณธ ์„ธํŒ…

 

์นด์นด์˜ค ๊ณต์‹๋ฌธ์„œ

์นด์นด์˜ค ๊ณต์‹๋ฌธ์„œ๋ฅผ ๋ณด๋ฉด, ๋Œ€๋žต์ ์œผ๋กœ ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ํ•ด๋‚˜๊ฐ€์•ผ ํ• ์ง€ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

 

 

๋Œ€๋žต

https://kauth.kakao.com/oauth/authorize?client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&response_type=code

์ด๋Ÿฌํ•œ ์ฃผ์†Œ๋กœ ์ ‘๊ทผ์„ ํ•˜๊ณ  ์ธ๊ฐ€ ์ฝ”๋“œ๋ฅผ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

์ด์ œ cliend_id์™€ redirect_uri๋ฅผ ๋ฐ›์•„์™€์„œ {CLIENT_ID}์™€ {REDIRECT_URI}์— ์ฑ„์›Œ์ฃผ์–ด์•ผ ํ•œ๋‹ค.

 

 

cliend_id

cliend_id๋Š” kakao developers์—์„œ ๋‚ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ถ”๊ฐ€ํ–ˆ์„ ๋•Œ ์ƒ๊ธฐ๋Š” REST_API ํ‚ค๋ฅผ ๋„ฃ์–ด์ค€๋‹ค.

 

 

ํ”Œ๋žซํผ ์ถ”๊ฐ€

Web์—์„œ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— Web ํ”Œ๋žซํผ์— ์‚ฌ์ดํŠธ ๋„๋ฉ”์ธ์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

๋ฐฐํฌํ•˜๊ธฐ ์ „์ด๊ธฐ ๋•Œ๋ฌธ์— localhost:3000์œผ๋กœ ์„ค์ •ํ–ˆ๋‹ค.

→ ๋ฐฐํฌํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด ๋ฐฐํฌํ•œ ์ฃผ์†Œ ์ถ”๊ฐ€ํ•˜๋ฉด ๋œ๋‹ค.

(port๋ฒˆํ˜ธ → frontend์˜ port๋ฒˆํ˜ธ)

 

 

Redirect URI

์นด์นด์˜ค ๋กœ๊ทธ์ธ์—์„œ ์‚ฌ์šฉํ•  OAuth Redirect URI๋ฅผ ์„ค์ •ํ•œ๋‹ค.

→ front์—์„œ

 

Redirect URI๋Š” ์นด์นด์˜ค ๋กœ๊ทธ์ธ ๋ฉ”๋‰ด์— ๋“ค์–ด๊ฐ€์„œ ์ถ”๊ฐ€๋ฅผ ํ•ด์ค€๋‹ค. ์ด๋•Œ ๊ฒฝ๋กœ ์„ค์ •์€ ๋ฐฑ์—”๋“œ์™€ ํ˜‘์˜ํ•ด์„œ ๋งž์ถ˜๋‹ค.

oauth/callback/kakao๋กœ redirect ์‹œํ‚ค๊ธฐ๋กœ ์ •ํ•˜๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋“ฑ๋กํ•ด์คฌ๋‹ค.

๐Ÿ’ก Redirect URI๋Š” ๋ฐ˜๋“œ์‹œ ํ”„๋ก ํŠธ์—์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” Host๋กœ ์ง€์ •ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค. → localhost:3000

์ด์œ  : ํ”„๋ŸฐํŠธ์—์„œ ์ธ๊ฐ€ ์ฝ”๋“œ ๋ฐ›๊ณ  ๋„˜๊ธฐ๊ณ  ๋“ฑ๋“ฑ ๋ชจ๋“  ์ž‘์—…์ด ์ด๋ฃจ์–ด์ ธ์•ผ ํ•˜๋Š”๋ฐ

ํ”„๋ก ํŠธ์—”๋“œ๊ฐ€ ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋Š” Host๋กœ ์ง€์ •์„ ํ•ด๋ฒ„๋ฆฌ๋ฉด(๋ฐฑ์—”๋“œ ํฌํŠธ๋ฒˆํ˜ธ๋กœ ๋ณด๋‚ด๋ฒ„๋ฆฐ๋‹ค๋˜์ง€)

์ ‘๊ทผ์ด ๋ถˆ๊ฐ€ํ•ด์„œ ์•„๋ฌด ์ž‘์—…๋„ ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

Process

์œ„์—์„œ ๋ดค๋˜ ์ด๋ฏธ์ง€ ํ๋ฆ„๋Œ€๋กœ ์ง„ํ–‰

 

Front์—์„œ ์นด์นด์˜ค ๋กœ๊ทธ์ธ์œผ๋กœ ์ธ๊ฐ€์ฝ”๋“œ ์š”์ฒญ

→ ์นด์นด์˜ค ๋กœ๊ทธ์ธ & ์„œ๋น„์Šค ์ด์šฉ๋“ฑ๋ก ์ˆ˜๋ฝ ๋“ฑ๋ก

→ Redirect ํ˜ธ์ถœ(Front)

→ ์ธ๊ฐ€์ฝ”๋“œ๋ฅผ ์ด์šฉํ•ด ํ† ํฐ์ •๋ณด ๋ฐ›๊ธฐ(Back)

→ ํ† ํฐ์ •๋ณด๋ฅผ ์ด์šฉํ•ด ์œ ์ €์ •๋ณด ๋ฐ›๊ธฐ(Back) → ์œ ์ € ๋“ฑ๋ก

→ ์œ ์ €์ •๋ณด ๋“ฑ๋ก ํ›„ JWT Token ๋ฆฌํ„ด(Back → Front)

 

 

1. kakao ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ํด๋ฆญ (Front) 

  • LoginPage.js
function socialLoginKakao() {
    console.log('kakao login clicked');
    AuthenticationService.loginSocialKakao();
}

 

  • AuthenticationService.js
loginSocialKakao() {
    window.location.href = KAKAO_AUTH_URL;
}

์นด์นด์˜ค ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ ์œ„์—์„œ ๋งŒ๋“  URL ์ฃผ์†Œ๋กœ ์—ฐ๊ฒฐ์„ ์‹œ์ผœ์ฃผ๋ฉด ๋œ๋‹ค.

(Client_ID์™€ KAKAO_AUTH_URL์€ OAuth.js ์—์„œ ๋”ฐ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ถ„๋ฆฌํ–ˆ๋‹ค.)

 

 

2. Redirect ํ˜ธ์ถœ(Front)

  • AuthenticationService.js ์ˆ˜์ •

kakaoLogin ๋น„๋™๊ธฐ ํ†ต์‹ ์„ ์œ„ํ•œ ๋ฉ”์†Œ๋“œ

async kakaoLogin(code) {
    return await axios.get(`/api/oauth/kakao?code=${code}`);
}

→ ๋ฐฑ์œผ๋กœ kakao์—์„œ ๋ฐ›์€ code๋ฅผ ๋„˜๊ธด๋‹ค.

 

  • ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋  ํ™”๋ฉด OAuth2RedirectHandeler.js
// ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋  ํ™”๋ฉด
// OAuth2RedirectHandeler.js
import React, { useEffect } from 'react';
import { Oval } from 'react-loader-spinner';
import { useNavigate } from 'react-router-dom';
import AuthenticationService from 'service/AuthenticationService';

const OAuth2RedirectHandler = (props) => {
    let params = new URL(document.URL).searchParams;
    let code = params.get('code');
    let navigate = useNavigate();

    useEffect(async () => {
        await AuthenticationService.kakaoLogin(code)
            .then((response) => {
                console.log('kakaoLogin');
                console.log(response.data.data.token);
                console.log(response.data.data.userEmail);
                AuthenticationService.registerSuccessfulLoginForJwt(response.data.data.userEmail, response.data.data.token);
            })
            .catch((error) => {
                console.log('kakaoLogin Failed');
            });
        navigate('/main');
    }, []);

    return (
        <div>
            <div>
                <div>์ž ์‹œ๋งŒ ๊ธฐ๋‹ค๋ ค ์ฃผ์„ธ์š”! ๋กœ๊ทธ์ธ ์ค‘์ž…๋‹ˆ๋‹ค.</div>

                <Oval height="80" width="80" radius="9" color="#00Bfff" ariaLabel="three-dots-loading" wrapperStyle wrapperClass />
            </div>
        </div>
    );
};

export default OAuth2RedirectHandler;

 

AuthenticationService.kakaoLogin ๋ฉ”์†Œ๋“œ๋ฅผ ์ž์„ธํžˆ ๋ณด๋ฉด,

await AuthenticationService.kakaoLogin(code)
    .then((response) => {
        console.log('kakaoLogin');
        console.log(response.data.data.token);
        console.log(response.data.data.userEmail);
        AuthenticationService.registerSuccessfulLoginForJwt(response.data.data.userEmail, response.data.data.token);
    })
    .catch((error) => {
        console.log('kakaoLogin Failed');
    });
navigate('/main');

→ ์„ฑ๊ณตํ•˜๋ฉด ์ผ๋ฐ˜ ๋กœ๊ทธ์ธ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ http๋กœ ์‘๋‹ต๋ฐ›์€ JWT Token์„ localStorage์— ์ €์žฅํ•˜๊ณ  ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌ๋˜๋ฉฐ ๋ฉ”์ธ์œผ๋กœ ์ด๋™

 

  • App.js ์ˆ˜์ •
import OAuth2RedirectHandler from 'service/OAuth2RedirectHandler';

:
:

<Route path="/oauth/callback/kakao" element={<OAuth2RedirectHandler />} />

App.js ์—์„œ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ ๊ฒฝ๋กœ ์„ค์ •(Redirect๋  ํ™”๋ฉด)

 

 

 

3. ์ธ๊ฐ€์ฝ”๋“œ๋ฅผ ์ด์šฉํ•ด ํ† ํฐ์ •๋ณด ๋ฐ›๊ธฐ(Back)

  • OauthController
@ApiOperation(value = "์นด์นด์˜ค ๋กœ๊ทธ์ธ", notes = "์นด์นด์˜ค ๋กœ๊ทธ์ธ")
@ResponseBody
@GetMapping("/kakao")
public void kakaoCallback(@ApiParam(value = "kakao auth code", required = true) @RequestParam String code) {
    String accessToken = oauthService.getKaKaoAccessToken(code);
}

โžก๏ธ front → back์œผ๋กœ parameter๋กœ code๋ฅผ ๋ฐ›๊ณ  ์ด ์ฝ”๋“œ๋ฅผ ์ด์šฉํ•ด KaKaoAccessToken์„ ๋ฐ›๋Š”๋‹ค.

 

 

  • OAuthService - getKaKaoAccessToken

code๋ฅผ ์ด์šฉํ•ด KaKaoAccessToken์„ ๋ฐ›๋Š” ๋ฉ”์†Œ๋“œ

public String getKaKaoAccessToken(String code) {

    String access_Token = "";
    String refresh_Token = "";
    String reqURL = "https://kauth.kakao.com/oauth/token";

    try {
        URL url = new URL(reqURL);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();

        //POST ์š”์ฒญ์„ ์œ„ํ•ด ๊ธฐ๋ณธ๊ฐ’์ด false์ธ setDoOutput์„ true๋กœ
        conn.setRequestMethod("POST");
        conn.setDoOutput(true);

        //POST ์š”์ฒญ์— ํ•„์š”๋กœ ์š”๊ตฌํ•˜๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ ์ŠคํŠธ๋ฆผ์„ ํ†ตํ•ด ์ „์†ก
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream()));
        StringBuilder sb = new StringBuilder();
        sb.append("grant_type=authorization_code");
        sb.append("&client_id=" + clientId); // TODO REST_API_KEY ์ž…๋ ฅ
        sb.append("&redirect_uri=" + redirectUri); // TODO ์ธ๊ฐ€์ฝ”๋“œ ๋ฐ›์€ redirect_uri ์ž…๋ ฅ
        sb.append("&code=" + code);
        bw.write(sb.toString());
        bw.flush();

        //๊ฒฐ๊ณผ ์ฝ”๋“œ๊ฐ€ 200์ด๋ผ๋ฉด ์„ฑ๊ณต
        int responseCode = conn.getResponseCode();
        System.out.println("responseCode : " + responseCode);
        //์š”์ฒญ์„ ํ†ตํ•ด ์–ป์€ JSONํƒ€์ž…์˜ Response ๋ฉ”์„ธ์ง€ ์ฝ์–ด์˜ค๊ธฐ
        BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        String line = "";
        String result = "";

        while ((line = br.readLine()) != null) {
            result += line;
        }
        System.out.println("response body : " + result);

        //Gson ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ํฌํ•จ๋œ ํด๋ž˜์Šค๋กœ JSONํŒŒ์‹ฑ ๊ฐ์ฒด ์ƒ์„ฑ
        JsonParser parser = new JsonParser();
        JsonElement element = parser.parse(result);

        access_Token = element.getAsJsonObject().get("access_token").getAsString();
        refresh_Token = element.getAsJsonObject().get("refresh_token").getAsString();

        System.out.println("access_token : " + access_Token);
        System.out.println("refresh_token : " + refresh_Token);

        br.close();
        bw.close();
    } catch (IOException e) {
        e.printStackTrace();
    }

    return access_Token;
}

 

 

4. ํ† ํฐ์ •๋ณด๋ฅผ ์ด์šฉํ•ด ์œ ์ €์ •๋ณด ๋ฐ›๊ธฐ(Back) → ์œ ์ € ๋“ฑ๋ก

KaKaoAccessToken์„ ํ†ตํ•ด ์นด์นด์˜ค์—์„œ ํ•„์š”ํ•œ ํ•ด๋‹น ์œ ์ €์˜ ์ •๋ณด๋ฅผ ๋ฐ›๋Š” ๋ฉ”์†Œ๋“œ

public HashMap<String, Object> getUserKakaoInfo(String access_Token) {

    // ์š”์ฒญํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ๋งˆ๋‹ค ๊ฐ€์ง„ ์ •๋ณด๊ฐ€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๊ธฐ์— HashMapํƒ€์ž…์œผ๋กœ ์„ ์–ธ
    HashMap<String, Object> userInfo = new HashMap<String, Object>();
    String reqURL = "https://kapi.kakao.com/v2/user/me";
    try {
        URL url = new URL(reqURL);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");

        // ์š”์ฒญ์— ํ•„์š”ํ•œ Header์— ํฌํ•จ๋  ๋‚ด์šฉ
        conn.setRequestProperty("Authorization", "Bearer " + access_Token);

        int responseCode = conn.getResponseCode();
        System.out.println("responseCode : " + responseCode);

        BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));

        String line = "";
        String result = "";

        while ((line = br.readLine()) != null) {
            result += line;
        }
        System.out.println("response body : " + result);

        JsonParser parser = new JsonParser();
        JsonElement element = parser.parse(result);

        String id = element.getAsJsonObject().get("id").getAsString();

        JsonObject properties = element.getAsJsonObject().get("properties").getAsJsonObject();
        JsonObject kakao_account = element.getAsJsonObject().get("kakao_account").getAsJsonObject();

        String nickname = properties.getAsJsonObject().get("nickname").getAsString();
        if(kakao_account.getAsJsonObject().get("email") != null){
            String email = kakao_account.getAsJsonObject().get("email").getAsString();
            userInfo.put("email", email);
        }

        userInfo.put("nickname", nickname);
        userInfo.put("id", id);

    } catch (IOException e) {
        e.printStackTrace();
    }
    return userInfo;
}

 

 

5. ์œ ์ €์ •๋ณด ๋“ฑ๋ก ํ›„ JWT Token ๋ฆฌํ„ด(Back → Front)

์œ„์—์„œ ์–ป์€ ์œ ์ € ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์šฐ๋ฆฌ ์œ ์ €์— ๋“ฑ๋กํ•œ ๋’ค, ์šฐ๋ฆฌ ์„œ๋ฒ„ ์ „์šฉ JWT Token์„ ํ”„๋ŸฐํŠธ๋กœ ๋„˜๊ฒจ์ค€๋‹ค.

 

Back

OAuthService.java

  • kakaoLogin

kakao๋กœ๊ทธ์ธ ์‹œ ์ด๋ฏธ ํšŒ์›๊ฐ€์ž…์ด ์ง„ํ–‰๋œ ์œ ์ €์ธ์ง€(์ด๋ฏธ ์นด์นด์˜ค ๋กœ๊ทธ์ธ ๋™์˜ํ•˜๊ณ  ๋“ฑ๋ก๋œ ์œ ์ €)ํ™•์ธํ•œ๋‹ค.

ํ™•์ธํ•˜๊ณ  userEmail์„ ์ด์šฉํ•ด ์ผ๋ฐ˜ ์œ ์ €์ฒ˜๋Ÿผ JWT Token์„ ๋ฐœ๊ธ‰ํ•˜์—ฌ return ํ•œ๋‹ค.

public UserKakaoLoginResponseDto kakaoLogin(String access_Token) {
    UserKakaoSignupRequestDto userKakaoSignupRequestDto = getUserKakaoSignupRequestDto(getUserKakaoInfo(access_Token));
    UserResponseDto userResponseDto = findByUserKakaoIdentifier(userKakaoSignupRequestDto.getUserKakaoIdentifier());
    if (userResponseDto == null){
        signUp(userKakaoSignupRequestDto);
        userResponseDto = findByUserKakaoIdentifier(userKakaoSignupRequestDto.getUserKakaoIdentifier());
    }

    String token = jwtTokenProvider.createToken(userResponseDto.getUserEmail());
    return new UserKakaoLoginResponseDto(HttpStatus.OK, token, userResponseDto.getUserEmail());
}

 

  • findByUserKakaoIdentifier

์ด๋ฏธ ํšŒ์›๊ฐ€์ž… ์ฒ˜๋ฆฌ๋œ ์นด์นด์˜ค ๋กœ๊ทธ์ธ ์œ ์ €์ธ์ง€ ํ™•์ธ.

public UserResponseDto findByUserKakaoIdentifier(String kakaoIdentifier) {
    List<User> user = userRepository.findUserByUserKakaoIdentifier(kakaoIdentifier).orElseThrow(() -> new UsernameNotFoundException("ํ•ด๋‹นํ•˜๋Š” ์œ ์ €๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."));

    if(user.size() == 0){
        return null;
    }
    return new UserResponseDto(user.get(0));
}

→ List๋กœ ๋˜์–ด์žˆ๋Š” ์ด์œ ๋Š” ์ผ๋ฐ˜ ์‚ฌ์šฉ์ž๋“ค์ผ ๊ฒฝ์šฐ kakaoIdentifier๊ฐ€ ํ•„์š”๊ฐ€ ์—†์–ด ์ผ๋‹จ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ  null๋กœ ๊ทธ๋ƒฅ ๋‘์—ˆ๋Š”๋ฐ, ๊ทธ๋ž˜์„œ entity์—์„œ ํ•ด๋‹น ๋ณ€์ˆ˜๋ฅผ unique๋‚˜ nullable ์ฒ˜๋ฆฌ๋ฅผ ํ•˜์ง€ ๋ชปํ•ด์„œ ์กฐํšŒ์‹œ List๋กœ ๋ถˆ๋Ÿฌ์™€์งˆ ๊ฐ€๋Šฅ์„ฑ ๋•Œ๋ฌธ์— JPA์ด์šฉ์‹œ ๋‹ค๊ฑด ์กฐํšŒ์™€ ์œ ์‚ฌํ•˜๊ฒŒ ์‚ฌ์šฉํ•ด์•ผ ํ•ด์„œ ์œ„์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ๋‘์—ˆ๋‹ค.

โ—๏ธ โžก๏ธ ์›๋ž˜๋Š” ์ผ๋ฐ˜์œ ์ €์—๊ฒŒ “-1”์ด๋‚˜ “0”๊ณผ ๊ฐ™์€ ๋””ํดํŠธ ๊ฐ’์„ ์ฃผ๊ณ  nullable = false์ฒ˜๋ฆฌ๋ผ๋„ ํ•˜๋Š” ๊ฒŒ ๋งž๋Š” ๊ฒƒ ๊ฐ™๋‹ค.

 

 

  • signUp

๋“ฑ๋ก๋˜์–ด ์žˆ์ง€ ์•Š์€ ์œ ์ €์ผ ๊ฒฝ์šฐ

kakao์—์„œ ๋ฐ›์€ user์˜ id๋ฅผ user_kakao_identifier๋กœ ๋“ฑ๋กํ•˜๊ณ , ๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ํ•„์š”ํ•˜์ง€ ์•Š์•„ -1๋กœ ๋‘๊ณ  ์ €์žฅํ•œ๋‹ค.

@Transactional
public Long signUp(UserKakaoSignupRequestDto userKakaoSignupRequestDto) throws BaseException {
    Long id;
    try {
        id = userRepository.save(userKakaoSignupRequestDto.toEntity()).getUserId();
    } catch (Exception e) {
        throw new BaseException(BaseResponseCode.FAILED_TO_SAVE_USER);
    }
    return id;
}

private UserKakaoSignupRequestDto getUserKakaoSignupRequestDto(HashMap<String, Object> userInfo){
    String userPassword = "-1";
    UserKakaoSignupRequestDto userKakaoSignupRequestDto = new UserKakaoSignupRequestDto(userInfo.get("email").toString(), userInfo.get("nickname").toString(),userPassword,userInfo.get("nickname").toString(),userInfo.get("id").toString());
    return userKakaoSignupRequestDto;
}

 

OAuthController.java

@ApiOperation(value = "์นด์นด์˜ค ๋กœ๊ทธ์ธ", notes = "์นด์นด์˜ค ๋กœ๊ทธ์ธ")
@ResponseBody
@GetMapping("/kakao")
public BaseResponse<UserLoginResponseDto> kakaoCallback(@ApiParam(value = "kakao auth code", required = true) @RequestParam String code) {
    String accessToken = oauthService.getKaKaoAccessToken(code);
    return new BaseResponse(oauthService.kakaoLogin(accessToken).getStatus(), "์š”์ฒญ ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.", oauthService.kakaoLogin(accessToken));
}

→ token๊ณผ ์ด๋ฉ”์ผ(ํ”„๋ŸฐํŠธ์—์„œ ํ˜„์žฌ ์œ ์ € ์ €์žฅํ•  ๋•Œ ํ•„์š”ํ•ด์„œ)์„ ๋ฆฌํ„ดํ•˜๋„๋ก ํ•œ๋‹ค.

 

Front

  • OAuth2RedirectHandeler.js

๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ๋  ํ™”๋ฉด์ธ๋ฐ ์—ฌ๊ธฐ์„œ ๋ณด๋ฉด

์‘๋‹ต๊ฒฐ๊ณผ์—์„œ userEmail๊ณผ token์„ ๊ฐ€์ง€๊ณ  ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌ ๋  ์ˆ˜ ์žˆ๋„๋ก ์ผ๋ฐ˜ ์œ ์ €์™€ ๋™์ผํ•˜๊ฒŒ JWTํ† ํฐ๊ณผ email์„ localStorage์— ์ €์žฅํ•  ์ˆ˜ ์žˆ๋„๋กํ–ˆ๋‹ค.

AuthenticationService.registerSuccessfulLoginForJwt(response.data.data.userEmail, response.data.data.token);

useEffect(async () => {
    await AuthenticationService.kakaoLogin(code)
        .then((response) => {
            console.log('kakaoLogin');
            console.log(response.data.data.token);
            console.log(response.data.data.userEmail);
            AuthenticationService.registerSuccessfulLoginForJwt(response.data.data.userEmail, response.data.data.token);
        })
        .catch((error) => {
            console.log('kakaoLogin Failed');
        });
    navigate('/main');
}, []);

 

 

front์—์„œ ์ฒ˜๋ฆฌํ•ด์ค˜์•ผ ํ•  ๋ถ€๋ถ„๊ณผ back์—์„œ ์ฒ˜๋ฆฌํ•  ๋ถ€๋ถ„์„ ์ž˜ ์ƒ๊ฐํ•˜๊ณ  ๋‚˜๋ˆ„๊ณ , ํ†ต์‹ ํ•˜๋ฉด ์ž˜ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ ๊ฐ™๋‹ค.

์ฒ˜์Œ์—๋Š” ์ข€ ํ—ค๋งธ๋Š”๋ฐ, ์นด์นด์˜ค ์†Œ์…œ ๋กœ๊ทธ์ธ ๋ฐฉ๋ฒ•์„ ๋งŽ์ด ์ฐพ์•„๋ณด๊ณ , ๊ณต์‹ ๋ฌธ์„œ๋„ ๋ณด๊ณ  ํ๋ฆ„์„ ์ดํ•ดํ•˜๋‹ˆ๊นŒ ๊ทธ ๋‹ค์Œ๋ถ€ํ„ฐ๋Š” ์ž˜ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์—ˆ๋˜ ๊ฒƒ ๊ฐ™๋‹ค..

 

๋ ๐Ÿง

 


Reference

๊ฐ์‚ฌํ•œ ๋ถ„๋“ค...๐Ÿฅฒ

 

https://velog.io/@ohjs813/Spring-%EC%B9%B4%EC%B9%B4%EC%98%A4-%EB%A1%9C%EA%B7%B8%EC%9D%B8-REST-API

 

δ Spring ์นด์นด์˜ค ๋กœ๊ทธ์ธ REST API

์ฐธ๊ณ ์šฉ์œผ๋กœ๋งŒ ๋ด์ฃผ์„ธ์š”! ์ •๋ง ์–ด . ๋ ต . ์Šต . ๋‹ˆ . ๋‹ค

velog.io

https://data-jj.tistory.com/53

 

REST-API ํ™œ์šฉํ•œ ์นด์นด์˜ค ์†Œ์…œ ๋กœ๊ทธ์ธ ๊ตฌํ˜„(feat. React)

ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด์„œ ์†Œ์…œ ๋กœ๊ทธ์ธ ๊ตฌํ˜„์„ ๋งก๊ฒŒ ๋˜์—ˆ๋‹ค. ๋‹ค๋“ค ํ”„๋ก ํŠธ์—”๋“œ๋Š” ์†Œ์…œ ๋กœ๊ทธ์ธ์—์„œ ํ• ๊ฒŒ ๋งŽ์ด ์—†๋‹ค ์‰ฝ๋‹ค~, ๊ทธ์ค‘์—์„œ ์นด์นด์˜ค๊ฐ€ ๊ฐ€์žฅ ์‰ฝ๋‹ค~ ์ด๋ ‡๊ฒŒ ์–˜๊ธฐํ•ด์„œ ๋ฐฉ์‹ฌํ–ˆ๋‹ค. ๊ทธ๋ ‡๊ฒŒ 6์ผ๊ฐ„์˜

data-jj.tistory.com

 

'Spring' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[Spring] Spring ์—๋Ÿฌ / Error creating bean with name 'sqlSessionFactory' defined in class path resource  (0) 2021.11.11

๋Œ“๊ธ€