Spring Boot์—์„œ ๊ตฌ๊ธ€ ์†Œ์…œ ๋กœ๊ทธ์ธ REST ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ•˜๊ธฐ
Web/Java (Spring+JSP)

Spring Boot์—์„œ ๊ตฌ๊ธ€ ์†Œ์…œ ๋กœ๊ทธ์ธ REST ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ•˜๊ธฐ

๐ŸŒŸGoal : Spring boot์—์„œ ๊ตฌ๊ธ€ ์†Œ์…œ ๋กœ๊ทธ์ธ์˜ ๋ฐฑ์—”๋“œ ์ฒ˜๋ฆฌ ํ”„๋กœ์„ธ์Šค๋ฅผ REST API ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ•œ๋‹ค.

 

1. ๊ตฌ๊ธ€ OAuth API ํ”„๋กœ์ ํŠธ ํ™˜๊ฒฝ ๊ตฌ์„ฑ

โฌ‡๏ธ ๊ตฌ๊ธ€ API๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์šฐ์„  ํ•˜๋‹จ์˜ ์‚ฌ์ดํŠธ์—์„œ ์ผ๋ จ์˜ ๊ตฌ์„ฑ๋ฐ ํ—ˆ๊ฐ€ ๊ณผ์ •์„ ๊ฑฐ์ณ์•ผ ํ•œ๋‹ค.

https://console.cloud.google.com/apis/dashboard 

 

Google Cloud Platform

ํ•˜๋‚˜์˜ ๊ณ„์ •์œผ๋กœ ๋ชจ๋“  Google ์„œ๋น„์Šค๋ฅผ Google Cloud Platform์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋กœ๊ทธ์ธํ•˜์„ธ์š”.

accounts.google.com

 

1) ์šฐ์„  ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์—ฌ์งˆ Oauth ๋™์˜ ํ™”๋ฉด์„ ๊ตฌ์„ฑํ•œ๋‹ค.

 

2) ๊ตฌ๊ธ€์˜ ์–ด๋–ค ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ๊นŒ์ง€ ์ ‘๊ทผํ•  ๊ฒƒ์ธ์ง€ ๋ฒ”์œ„๋ฅผ ์ง€์ •ํ•œ๋‹ค.

3) ํ…Œ์ŠคํŠธ ์‚ฌ์šฉ์ž ์ถ”๊ฐ€๋Š” ์šฐ์„  ์ƒ๋žตํ•˜๊ณ , ์™„๋ฃŒํ•˜๋ฉด ์‚ฌ์šฉ์ž Oauth ๋™์˜ ํ™”๋ฉด์ด ๊ตฌ์„ฑ๋œ๋‹ค.

 

 

4) OAuth api์— ์•ก์„ธ์Šคํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด๋ฅผ ๋ฐœ๊ธ‰ํ•ด์•ผ ํ•œ๋‹ค.

  • ์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ๊ฒƒ์€ ์Šน์ธ๋œ ๋ฆฌ๋””๋ ‰์…˜ URI์ธ๋ฐ, ๊ตฌ๊ธ€ ๋กœ๊ทธ์ธ์ด ๋๋‚˜๊ณ  ๋‚œ ๋’ค์— ํ•ด๋‹น api๋กœ ๋ฆฌ๋””๋ ‰์…˜๋˜์–ด ์•ก์„ธ์Šค ํ† ํฐ ๋“ฑ์„ ์ฒ˜๋ฆฌํ•˜๋ฏ€๋กœ path๋ฅผ ํ™•์ธํ•˜์—ฌ ์ž˜ ์ง€์ •ํ•ด๋‘ฌ์•ผ ํ•œ๋‹ค.

5) ํ•ด๋‹น ๊ณผ์ •์„ ๊ฑฐ์น˜๋ฉด ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด๊ฐ€ ๋ฐœ๊ธ‰๋œ๋‹ค. ์ถ”ํ›„์— ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋ฏ€๋กœ ์ž˜ ํ™•์ธํ•ด๋‘์ž.

 

 

2. REST API ๊ตฌํ˜„

  • SNS ์†Œ์…œ ๋กœ๊ทธ์ธ ํ”„๋กœ์„ธ์Šค
    • ๋กœ๊ทธ์ธ ์ตœ์ดˆ ์š”์ฒญ ์ฒ˜๋ฆฌ (”/app/accounts/auth/{SocialLoginType}”)
      • ์ฒซ๋ฒˆ์งธ๋กœ ์‚ฌ์šฉ์ž๊ฐ€ ์›น์‚ฌ์ดํŠธ์˜ ๋กœ๊ทธ์ธ ํ™”๋ฉด์—์„œ ํŠน์ •ํ•œ ์†Œ์…œ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๊ฒŒ ๋˜๋Š”๋ฐ, ๋จผ์ € ์ด ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•œ๋‹ค.
      • ์ด ์š”์ฒญ์€ ์ •ํ•ด์ง„ ํ˜•์‹์œผ๋กœ URL์„ ๊ฐ–์ถฐ( ๊ฐ api ๊ฐ ์†Œ์…œ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธํ•ด์คŒ์œผ๋กœ์จ ์ฒ˜๋ฆฌํ•œ๋‹ค.
    • ์†Œ์…œ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€์—์„œ ๋กœ๊ทธ์ธํ•œ ์ดํ›„ ์Šน์ธ๋œ ๋ฆฌ๋””๋ ‰์…˜ URI๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋œ๋‹ค.(”/app/accounts/auth/{SocialLoginType}/callback”)
      • ์ด๋•Œ ํ•ด๋‹น API ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ 1ํšŒ์šฉ access code๋ฅผ ๋ฐ›๊ฒŒ ๋˜๋Š”๋ฐ, ์ด ์ฝ”๋“œ๋ฅผ ์ด์šฉํ•ด api ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ access token๊ณผ refresh token์„ ๋ฐ›๊ฒŒ ๋œ๋‹ค.
    • ์ด access token์„ ์ด์šฉํ•ด์„œ ์ธ๊ฐ€ ์ฒ˜๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜๋ฉฐ, ์†Œ์…œ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ์‚ฌ์šฉ์ž์˜ ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ์š”์ฒญํ• ๋•Œ๋„ ์ด access token์„ ์‚ฌ์šฉํ•˜์—ฌ ์ •๋ณด๋ฅผ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ๋‹ค.
  • ์†Œ์…œ ๋กœ๊ทธ์ธ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ํ•ด๋‹น ์„œ๋“œํŒŒํ‹ฐ์™€ ๋ฐ˜๋“œ์‹œ ์ •ํ•ด์ง„ ํ˜•์‹์— ๋งž์ถฐ์„œ response/request๋ฅผ ์ง„ํ–‰ํ•ด์•ผ ํ•œ๋‹ค. 
    • ๋‚˜๊ฐ™์€ ๊ฒฝ์šฐ๋Š” REST API๋ฅผ ๊ตฌํ˜„ํ•  ์˜ˆ์ •์ด๋ฏ€๋กœ HTTP/REST ๊ทœ์•ฝ ๋ถ€๋ถ„์„ ์ฐธ๊ณ ํ•ด์„œ ๊ฐœ๋ฐœํ•˜์˜€๋‹ค.

โฌ‡๏ธ ํ•˜๋‹จ ์‚ฌ์ดํŠธ๋ฅผ ๋ฐ˜๋“œ์‹œ ์ฐธ๊ณ ํ•˜๋ฉด์„œ ๊ตฌํ˜„ํ•  ๊ฒƒ.

https://developers.google.com/identity/protocols/oauth2/web-server#libraries

 

์›น ์„œ๋ฒ„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— OAuth 2.0 ์‚ฌ์šฉ  |  Google ID ํ”Œ๋žซํผ  |  Google Developers

์ด ํŽ˜์ด์ง€๋Š” Cloud Translation API๋ฅผ ํ†ตํ•ด ๋ฒˆ์—ญ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. Switch to English ์›น ์„œ๋ฒ„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— OAuth 2.0 ์‚ฌ์šฉ ์ด ๋ฌธ์„œ์—์„œ๋Š” ์›น ์„œ๋ฒ„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด Google API ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋˜๋Š” Google OAuth

developers.google.com

 

1) ๋กœ๊ทธ์ธ ์ตœ์ดˆ ์š”์ฒญ ์ฒ˜๋ฆฌ

  1. ์†Œ์…œ ๋กœ๊ทธ์ธ ํƒ€์ž…์„ ๊ตฌ๋ณ„ํ•˜๊ธฐ ์œ„ํ•ด์„œ enum ํ˜•์‹์„ constant๋กœ ๋งŒ๋“ค์–ด์ค€๋‹ค.

package com.example.demo.config;

public class Constant {
    public enum SocialLoginType{
        GOOGLE,
        KAKAO,
        NAVER
    }
}

 

2. ๊ฐ ์†Œ์…œ ๋กœ๊ทธ์ธ ํด๋ž˜์Šค๊ฐ€ ์ƒ์†๋ฐ›์•„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก interface๋ฅผ ํ•˜๋‚˜ ์ƒ์„ฑํ•œ๋‹ค.

package com.example.demo.src.account.social;

public interface SocialOauth {
    /**
     * ๊ฐ ์†Œ์…œ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ redirectํ•  URL build
     * ์‚ฌ์šฉ์ž๋กœ๋ถ€ํ„ฐ ๋กœ๊ทธ์ธ ์š”์ฒญ์„ ๋ฐ›์•„ ์†Œ์…œ ๋กœ๊ทธ์ธ ์„œ๋ฒ„ ์ธ์ฆ์šฉ ์ฝ”๋“œ ์š”์ฒญ
     */
    String getOauthRedirectURL();
}

 

3. ์†Œ์…œ ๋กœ๊ทธ์ธ ํƒ€์ž…๋ณ„ ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

  • ์˜ค๋Š˜์€ ๊ตฌ๊ธ€ ๋กœ๊ทธ์ธ์„ ๊ตฌํ˜„ํ•  ์˜ˆ์ •์ด๋ฏ€๋กœ ๊ตฌ๊ธ€ ํด๋ž˜์Šค๋งŒ ์ƒ์„ฑํ•ด๋‘๋„๋ก ํ•˜๊ฒ ๋‹ค.
  • ์ฐจํ›„์— ๋‹ค์–‘ํ•œ ๋กœ๊ทธ์ธ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ๋“ค๊ณ  ์„ธ๋ถ€ ํด๋ž˜์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋Š”๊ฒŒ ์œ ์ง€๋ณด์ˆ˜์— ์ข‹๋‹ค.
@Component
@RequiredArgsConstructor
public class GoogleOauth implements SocialOauth {
@Override
    public String getOauthRedirectURL(){
    return "";}
    }

 

4. ๋กœ๊ทธ์ธ ๋ฐฉ์‹์— ๋”ฐ๋ผ์„œ ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ ํ˜ธ์ถœํ•ด์ค„ Service class๋ฅผ ํ•˜๋‚˜ ์ƒ์„ฑํ•œ๋‹ค.

@Service
@RequiredArgsConstructor
public class OAuthService {
    private final GoogleOauth googleOauth;
    private final HttpServletResponse response;

    public void request(Constant.SocialLoginType socialLoginType) throws IOException {
        String redirectURL;
        switch (socialLoginType){
            case GOOGLE:{
                //๊ฐ ์†Œ์…œ ๋กœ๊ทธ์ธ์„ ์š”์ฒญํ•˜๋ฉด ์†Œ์…œ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ํ•ด์ฃผ๋Š” ํ”„๋กœ์„ธ์Šค์ด๋‹ค.
                redirectURL= googleOauth.getOauthRedirectURL();
            }break;
            default:{
                throw new IllegalArgumentException("์•Œ ์ˆ˜ ์—†๋Š” ์†Œ์…œ ๋กœ๊ทธ์ธ ํ˜•์‹์ž…๋‹ˆ๋‹ค.");
            }

        }

        response.sendRedirect(redirectURL);
    }
}

 

5. ๋กœ๊ทธ์ธ์„ ์ฃผ๊ด€ํ•˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ ํด๋ž˜์Šค(AccountController)์—์„œ ์†Œ์…œ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ํ•ด์ค„ API๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค. 

  • path๋กœ ์–ด๋–ค ๊ฐ’์ด ๋“ค์–ด์˜ค๋Š๋ƒ์— ๋”ฐ๋ผ์„œ ์ด์ œ service ๊ฐ์ฒด์—์„œ switch๋ฌธ์œผ๋กœ ๋‹ค๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•  ๊ฒƒ์ด๋‹ค.
  • localhost:9000/app/acoounts/auth/google๋กœ ์š”์ฒญ์ด ๋“ค์–ด์˜จ๋‹ค๋ฉด, googleOauth๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ ๋  ๊ฒƒ์ด๋‹ค.
 /**
     * ์œ ์ € ์†Œ์…œ ๋กœ๊ทธ์ธ์œผ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ํ•ด์ฃผ๋Š” url
      * [GET] /accounts/auth
     * @return void
     */
    @NoAuth
    @GetMapping("/auth/{socialLoginType}") //GOOGLE์ด ๋“ค์–ด์˜ฌ ๊ฒƒ์ด๋‹ค.
    public void socialLoginRedirect(@PathVariable(name="socialLoginType") String SocialLoginPath) throws IOException {
             SocialLoginType socialLoginType= SocialLoginType.valueOf(SocialLoginPath.toUpperCase());
             oAuthService.request(socialLoginType);
    }

 

6. GoogleOauth ํด๋ž˜์Šค ์ƒ์„ธ๊ตฌํ˜„

  1) resource ํด๋”์— ์กด์žฌํ•˜๋Š” applications.yml ์— ์•„๊นŒ ๋ฐœ๊ธ‰๋ฐ›์€ client id, client secret key๋“ฑ์„ ๋“ฑ๋กํ•ด์ค€๋‹ค. ์ด๋Š” ๋…ธ์ถœ๋˜๋ฉด ์•ˆ๋˜๋ฏ€๋กœ ์ฝ”๋“œ์— ์ง์ ‘ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๊ณ  yml ํŒŒ์ผ์—์„œ ๋ถˆ๋Ÿฌ์™€์„œ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋‹ค.

2) ๊ตฌ๊ธ€ api ๋ฌธ์„œ๋ฅผ ํ™•์ธํ•˜์—ฌ ๊ตฌ๊ธ€ ์†Œ์…œ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋””๋ ‰์…˜ ํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ URL์„ ๊ตฌ์„ฑํ•ด์•ผ ํ•˜๋Š”์ง€ ํ™•์ธํ–ˆ๋‹ค.

  • ํ˜„์žฌ response.redirect(URL); ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ณง๋ฐ”๋กœ redirect๋ฅผ ์‹œํ‚ค๊ณ  ์žˆ์œผ๋ฉฐ url์„ controller๋กœ ๋‹ค์‹œ ๋„˜๊ฒจ์ฃผ๊ธฐ๋งŒ ํ•˜๋ฉด ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋””๋ ‰์…˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

3) URL์„ ๊ตฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด GoogleOauth class์— ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

@Component
@RequiredArgsConstructor
public class GoogleOauth implements SocialOauth {

    //applications.yml ์—์„œ value annotation์„ ํ†ตํ•ด์„œ ๊ฐ’์„ ๋ฐ›์•„์˜จ๋‹ค.
    @Value("${spring.OAuth2.google.url}")
    private String GOOGLE_SNS_LOGIN_URL;

    @Value("${spring.OAuth2.google.client-id}")
    private String GOOGLE_SNS_CLIENT_ID;

    @Value("${spring.OAuth2.google.callback-url}")
    private String GOOGLE_SNS_CALLBACK_URL;

    @Value("${spring.OAuth2.google.client-secret}")
    private String GOOGLE_SNS_CLIENT_SECRET;

    @Value("${spring.OAuth2.google.scope}")
    private String GOOGLE_DATA_ACCESS_SCOPE;

    private final ObjectMapper objectMapper;
    @Override
    public String getOauthRedirectURL(){

        Map<String,Object> params=new HashMap<>();
        params.put("scope",GOOGLE_DATA_ACCESS_SCOPE);
        params.put("response_type","code");
        params.put("client_id",GOOGLE_SNS_CLIENT_ID);
        params.put("redirect_uri",GOOGLE_SNS_CALLBACK_URL);

        //parameter๋ฅผ ํ˜•์‹์— ๋งž์ถฐ ๊ตฌ์„ฑํ•ด์ฃผ๋Š” ํ•จ์ˆ˜
        String parameterString=params.entrySet().stream()
                .map(x->x.getKey()+"="+x.getValue())
                .collect(Collectors.joining("&"));
        String redirectURL=GOOGLE_SNS_LOGIN_URL+"?"+parameterString;
        System.out.println("redirectURL = " + redirectURL);

        return redirectURL;
        /*
        * https://accounts.google.com/o/oauth2/v2/auth?scope=profile&response_type=code
        * &client_id="ํ• ๋‹น๋ฐ›์€ id"&redirect_uri="access token ์ฒ˜๋ฆฌ")
        * ๋กœ Redirect URL์„ ์ƒ์„ฑํ•˜๋Š” ๋กœ์ง์„ ๊ตฌ์„ฑ
        * */
    }
  • ์ด์ œ ํ•ด๋‹น ๋ฉ”์†Œ๋“œ์—์„œ url์„ ๊ตฌ์„ฑํ•ด service๋กœ ๋„˜๊ฒจ์ฃผ๋ฉด service->controller๋ฅผ ๊ฑฐ์ณ ํ•ด๋‹น url์„ ํ†ตํ•ด์„œ ์†Œ์…œ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋จ.

 

7. Postman์œผ๋กœ ํ…Œ์ŠคํŠธ

  • localhost:9000/app/accounts/auth/google ๋กœ requestํ•˜๋ฉด ์ผ๋ จ์˜ ๊ณผ์ •์„ ๊ฑฐ์ณ ์†Œ์…œ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๊ฐ€ ๋ Œ๋”๋ง๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

  • ๊ตฌ๊ธ€์— ๋ฏธ๋ฆฌ ๋กœ๊ทธ์ธ๋˜์–ด ์žˆ๋Š” ํฌ๋กฌ ํ™˜๊ฒฝ์—์„œ ์œ„์˜ url๋กœ ์ ‘์†ํ•ด๋ณด์•˜๋‹ค.
  • ๊ณง๋ฐ”๋กœ ์†Œ์…œ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋˜์–ด ์ €์žฅ๋˜์–ด์žˆ๋Š” ํ”„๋กœํ•„ ํŽ˜์ด์ง€๊ฐ€ ๋ Œ๋”๋ง๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.
  • ํ”„๋กœํ•„์„ ์„ ํƒํ•˜๊ณ  ๋‚˜๋ฉด ์ด์ „์— ๋‚จ์€ ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌ๋ฅผ ์ง„ํ–‰ํ•  redirect_uri๋กœ ์ง€์ •ํ–ˆ๋˜ url๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋œ๋‹ค.

์ด code ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์šฐ๋ฆฌ๊ฐ€ ์ถ”ํ›„์— ์‚ฌ์šฉํ•  ์ผํšŒ์„ฑ ์ฝ”๋“œ์ด๋‹ค.

 

2) ์†Œ์…œ ๋กœ๊ทธ์ธ ์ดํ›„ ์š”์ฒญ ์ฒ˜๋ฆฌ

1. ์ด์ „์— ๊ตฌ๊ธ€์— ๋“ฑ๋กํ•ด๋’€๋˜ callback api๋ฅผ controller์—์„œ ๊ฐœ๋ฐœํ•œ๋‹ค.

  • ์†Œ์…œ ๋กœ๊ทธ์ธ๊ณผ ๊ด€๋ จ๋œ ์„œ๋น„์Šค๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” oAuthService ์œผ๋กœ ์†Œ์…œ ๋กœ๊ทธ์ธ ๊ฒฐ๊ณผ๋กœ ๋ฐ›์•„์˜จ ์ผํšŒ์„ฑ ์ฝ”๋“œ๋ฅผ ๋ณด๋‚ด์„œ ์„œ๋“œํŒŒํ‹ฐ๋กœ๋ถ€ํ„ฐ ์•ก์„ธ์Šค ํ† ํฐ์„ ๋ฐ›์•„์˜ค๊ณ , ๊ทธ ์•ก์„ธ์Šค ํ† ํฐ์„ ๋‹ค์‹œ ๋ณด๋‚ด ์„œ๋“œํŒŒํ‹ฐ์— ์ €์žฅ๋œ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๋ฐ›์•„์˜ค๋Š” ์ผ๋ จ์˜ ๊ณผ์ •์„ ๊ฑฐ์น  ๊ฒƒ์ด๋‹ค.
  • ๊ทธ ๊ณผ์ •์˜ ๊ฒฐ๊ณผ๋กœ ๋‹ค์‹œ ์„œ๋ฒ„์— ์ •๋ณด๋ฅผ ์š”์ฒญํ• ๋•Œ ํ•„์š”ํ•œ access_token, ์šฐ๋ฆฌ ์„œ๋ฒ„์—์„œ ํšŒ์› ์ธ๊ฐ€์ฒ˜๋ฆฌ๋ฅผ ํ•  jwt_token, ๊ทธ๋ฆฌ๊ณ  ์ถ”ํ›„์— ์กฐํšŒ๋“ฑ์— ํ•„์š”ํ•œ user_num๋“ฑ์˜ ์ •๋ณด๋ฅผ ๋ฐ›์•„์˜ฌ ๊ฒƒ์ด๋‹ค.
  /**
     * Social Login API Server ์š”์ฒญ์— ์˜ํ•œ callback ์„ ์ฒ˜๋ฆฌ
     * @param socialLoginPath (GOOGLE, FACEBOOK, NAVER, KAKAO)
     * @param code API Server ๋กœ๋ถ€ํ„ฐ ๋„˜์–ด์˜ค๋Š” code
     * @return SNS Login ์š”์ฒญ ๊ฒฐ๊ณผ๋กœ ๋ฐ›์€ Json ํ˜•ํƒœ์˜ java ๊ฐ์ฒด (access_token, jwt_token, user_num ๋“ฑ)
     */

   @NoAuth
    @ResponseBody
    @GetMapping(value = "/auth/{socialLoginType}/callback")
    public BaseResponse<GetSocialOAuthRes> callback (
            @PathVariable(name = "socialLoginType") String socialLoginPath,
            @RequestParam(name = "code") String code)throws IOException,BaseException{
        System.out.println(">> ์†Œ์…œ ๋กœ๊ทธ์ธ API ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ code :"+ code);
        SocialLoginType socialLoginType= SocialLoginType.valueOf(socialLoginPath.toUpperCase());
        GetSocialOAuthRes getSocialOAuthRes=oAuthService.oAuthLogin(socialLoginType,code);
        return new BaseResponse<>(getSocialOAuthRes);
    }

 

2. ์šฐ์„  model์„ ๋ชจ์•„๋‘” ํŒจํ‚ค์ง€์— ์„œ๋ฒ„์™€ ํ†ต์‹ ํ•˜๊ธฐ ์œ„ํ•œ ์—ฌ๋Ÿฌ ์ž๋ฐ” ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ ๋‹ค.

//๊ตฌ๊ธ€์— ์ผํšŒ์„ฑ ์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ๋ณด๋‚ด ๋ฐ›์•„์˜ฌ ์•ก์„ธ์Šค ํ† ํฐ์„ ํฌํ•จํ•œ JSON ๋ฌธ์ž์—ด์„ ๋‹ด์„ ํด๋ž˜์Šค
@AllArgsConstructor
@Getter
@Setter
public class GoogleOAuthToken {
    private String access_token;
    private int expires_in;
    private String scope;
    private String token_type;
    private String id_token;
}
//๊ตฌ๊ธ€(์„œ๋“œํŒŒํ‹ฐ)๋กœ ์•ก์„ธ์Šค ํ† ํฐ์„ ๋ณด๋‚ด ๋ฐ›์•„์˜ฌ ๊ตฌ๊ธ€์— ๋“ฑ๋ก๋œ ์‚ฌ์šฉ์ž ์ •๋ณด
@AllArgsConstructor
@Getter
@Setter
public class GoogleUser {
    public String id;
    public String email;
    public Boolean verifiedEmail;
    public String name;
    public String givenName;
    public String familyName;
    public String picture;
    public String locale;
}
//ํด๋ผ์ด์–ธํŠธ๋กœ ๋ณด๋‚ผ jwtToken, accessToken๋“ฑ์ด ๋‹ด๊ธด ๊ฐ์ฒด
@Getter
@Setter
@AllArgsConstructor
public class GetSocialOAuthRes {

    private String jwtToken;
    private int user_num;
    private String accessToken;
    private String tokenType;
}

 

 

3. ์ด์ œ oAuthService ํด๋ž˜์Šค์— ์ „๋ฐ˜์ ์ธ ๊ตฌ๊ธ€๊ณผ์˜ ํ†ต์‹  ํ”„๋กœ์„ธ์Šค๋ฅผ ์ฒ˜๋ฆฌํ•  oAuthLogin ๋ฉ”์†Œ๋“œ๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๋„๋ก ํ•˜๊ฒ ๋‹ค.

 public GetSocialOAuthRes oAuthLogin(Constant.SocialLoginType socialLoginType, String code) throws IOException {

        switch (socialLoginType){
            case GOOGLE:{
                //๊ตฌ๊ธ€๋กœ ์ผํšŒ์„ฑ ์ฝ”๋“œ๋ฅผ ๋ณด๋‚ด ์•ก์„ธ์Šค ํ† ํฐ์ด ๋‹ด๊ธด ์‘๋‹ต๊ฐ์ฒด๋ฅผ ๋ฐ›์•„์˜ด
                ResponseEntity<String> accessTokenResponse= googleOauth.requestAccessToken(code);
               //์‘๋‹ต ๊ฐ์ฒด๊ฐ€ JSONํ˜•์‹์œผ๋กœ ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ, ์ด๋ฅผ deserializationํ•ด์„œ ์ž๋ฐ” ๊ฐ์ฒด์— ๋‹ด์„ ๊ฒƒ์ด๋‹ค.
               GoogleOAuthToken oAuthToken=googleOauth.getAccessToken(accessTokenResponse);
               
               //์•ก์„ธ์Šค ํ† ํฐ์„ ๋‹ค์‹œ ๊ตฌ๊ธ€๋กœ ๋ณด๋‚ด ๊ตฌ๊ธ€์— ์ €์žฅ๋œ ์‚ฌ์šฉ์ž ์ •๋ณด๊ฐ€ ๋‹ด๊ธด ์‘๋‹ต ๊ฐ์ฒด๋ฅผ ๋ฐ›์•„์˜จ๋‹ค.
                ResponseEntity<String> userInfoResponse=googleOauth.requestUserInfo(oAuthToken);
                //๋‹ค์‹œ JSON ํ˜•์‹์˜ ์‘๋‹ต ๊ฐ์ฒด๋ฅผ ์ž๋ฐ” ๊ฐ์ฒด๋กœ ์—ญ์ง๋ ฌํ™”ํ•œ๋‹ค.
                GoogleUser googleUser= googleOauth.getUserInfo(userInfoResponse);

                }

            }
            default:{
                throw new IllegalArgumentException("์•Œ ์ˆ˜ ์—†๋Š” ์†Œ์…œ ๋กœ๊ทธ์ธ ํ˜•์‹์ž…๋‹ˆ๋‹ค.");
            }

        }

 

4. ๊ตฌ๊ธ€๊ณผ ํ†ต์‹ ํ•˜๊ธฐ ์œ„ํ•œ ์—ฌ๋Ÿฌ ๋ฉ”์†Œ๋“œ๋ฅผ GoogleOAuth ํด๋ž˜์Šค์— ๊ฐœ๋ฐœํ•œ๋‹ค.

 1) ๋จผ์ € ์ผํšŒ์šฉ ์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ๊ตฌ๊ธ€๋กœ ๋ณด๋‚ด ์•ก์„ธ์Šค ํ† ํฐ์„ ํฌํ•จํ•œ JSON String์ด ๋‹ด๊ธด ResponseEntity๋ฅผ ๋ฐ›์•„์˜จ๋‹ค.

   - ์•ก์„ธ์Šค ํ† ํฐ์„ ๋ฐ›์•„์˜ค๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ๋“ค์€ ๊ตฌ๊ธ€ ๊ณต์‹ ๋ฌธ์„œ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

public ResponseEntity<String> requestAccessToken(String code) {
        String GOOGLE_TOKEN_REQUEST_URL="https://oauth2.googleapis.com/token";
        RestTemplate restTemplate=new RestTemplate();
        Map<String, Object> params = new HashMap<>();
        params.put("code", code);
        params.put("client_id", GOOGLE_SNS_CLIENT_ID);
        params.put("client_secret", GOOGLE_SNS_CLIENT_SECRET);
        params.put("redirect_uri", GOOGLE_SNS_CALLBACK_URL);
        params.put("grant_type", "authorization_code");

        ResponseEntity<String> responseEntity=restTemplate.postForEntity(GOOGLE_TOKEN_REQUEST_URL,
                params,String.class);

        if(responseEntity.getStatusCode()== HttpStatus.OK){
            return responseEntity;
        }
        return null;
    }

+) RestTemplate

  • Spring boot์—์„œ๋Š” ๋‹ค๋ฅธ ์„œ๋ฒ„์˜ API endpoint๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ RestTemplate๋ฅผ ๋งŽ์ด ์“ด๋‹ค.
  • HTTP ์„œ๋ฒ„์™€์˜ ํ†ต์‹ ์„ ๋‹จ์ˆœํ™”ํ•˜๊ณ  RESTful ์›์น™์„ ์ง€ํ‚จ๋‹ค.(json, xml์„ ์‰ฝ๊ฒŒ ์‘๋‹ต ๋ฐ›๋Š”๋‹ค.
//์šฐ์„  RestTemplate๋ฅผ ๋งค๋ฒˆ ์ƒˆ๋กœ ์ƒ์„ฑํ•˜๊ธฐ ๋ณด๋‹ค ๋นˆ์œผ๋กœ ๋งŒ๋“ค์–ด์„œ ์˜์กด์„ฑ์„ ์ฃผ์ž…๋ฐ›๋„๋ก ํ•œ๋‹ค.
@Configuration
public class RestTemplateConfig {
    //HTTP get,post ์š”์ฒญ์„ ๋‚ ๋ฆด๋•Œ ์ผ์ •ํ•œ ํ˜•์‹์— ๋งž์ถฐ์ฃผ๋Š” template
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
        return restTemplateBuilder
                .requestFactory(() -> new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()))
                .additionalMessageConverters(new StringHttpMessageConverter(Charset.forName("UTF-8")))
                .build();
    }
}

//ํ™œ์šฉ ์˜ˆ์‹œ
restTemplate.exchange(url, httpMethod, new HttpEntity<>(body, httpHeaders), class);
restTemplate.postForEntity(url, parameter,class);

responseEntity์— ๋‹ด๊ธด Body๋‚ด์šฉ์ด๋‹ค.

2) responseEntity์— ๋‹ด๊ธด JSON String์„ ์—ญ์ง๋ ฌํ™”ํ•ด ์ž๋ฐ” ๊ฐ์ฒด์— ๋‹ด๋Š”๋‹ค.

 public GoogleOAuthToken getAccessToken(ResponseEntity<String> response) throws JsonProcessingException {
        System.out.println("response.getBody() = " + response.getBody());
        GoogleOAuthToken googleOAuthToken= objectMapper.readValue(response.getBody(),GoogleOAuthToken.class);
        return googleOAuthToken;

    }

 

3) ๋‹ค์‹œ ๊ตฌ๊ธ€๋กœ ์•ก์„ธ์Šค ํ† ํฐ์„ ๋ณด๋‚ด ๊ตฌ๊ธ€ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๋ฐ›์•„์˜จ๋‹ค.

  • ์—ญ์‹œ ๊ตฌ๊ธ€ api ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•ด request ํ˜•์‹์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌ์„ฑํ•ด์•ผ ํ•œ๋‹ค.
  • ์ด์ „์— ๊ณ„์† ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ request๋ฅผ ๋ณด๋ƒˆ์œผ๋‹ˆ, ์ด๋ฒˆ์—” ํ—ค๋”์— access token์„ ๋‹ด๋Š” ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ•ด ๋ณด์•˜๋‹ค.

 public ResponseEntity<String> requestUserInfo(GoogleOAuthToken oAuthToken) {
        String GOOGLE_USERINFO_REQUEST_URL="https://www.googleapis.com/oauth2/v1/userinfo";

	//header์— accessToken์„ ๋‹ด๋Š”๋‹ค.
        HttpHeaders headers = new HttpHeaders();
        headers.add("Authorization","Bearer "+oAuthToken.getAccess_token());
        
        //HttpEntity๋ฅผ ํ•˜๋‚˜ ์ƒ์„ฑํ•ด ํ—ค๋”๋ฅผ ๋‹ด์•„์„œ restTemplate์œผ๋กœ ๊ตฌ๊ธ€๊ณผ ํ†ต์‹ ํ•˜๊ฒŒ ๋œ๋‹ค.
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity(headers);
        ResponseEntity<String> response=restTemplate.exchange(GOOGLE_USERINFO_REQUEST_URL, HttpMethod.GET,request,String.class);
        System.out.println("response.getBody() = " + response.getBody());
        return response;
    }

access token์„ ๋ณด๋ƒˆ์„ ๋•Œ ๋Œ์•„์˜ค๋Š” response ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

< ๊ธฐ๋ณธ ๊ฐœ๋… ์ •๋ฆฌ>

  • HttpHeaders
    • Header์— ์›ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ key-value๊ฐ’์„ ์„ค์ •ํ•ด์„œ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด์ด๋‹ค.
    • Spring.io์˜ ์„ค๋ช…์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

 

  • HTTPEntity<T>
    • HTTPEntity๋Š” http ์š”์ฒญ/์‘๋‹ต์— ํ•ด๋‹นํ•˜๋Š” HTTPHeader์™€ HTTPBody๋ฅผ ํฌํ•จํ•˜๋Š” ๊ฐ์ฒด์ด๋‹ค.
    • ๋”ฐ๋ผ์„œ HttpEntity๋ฅผ ์ƒ์„ฑํ• ๋•Œ header๋ฅผ ์ƒ์„ฑ์ž ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.
public class HttpEntity<T> {
    public static final HttpEntity<?> EMPTY = new HttpEntity();
    private final HttpHeaders headers;
    private final T body;
    ...
}

 

  • ResponseEntity
    • ์ผ๋ฐ˜์ ์ธ API๋Š” ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฆฌ์†Œ์Šค์— Value๋งŒ ์žˆ์ง€ ์•Š์œผ๋ฉฐ, ์ƒํƒœ ์ฝ”๋“œ, ์‘๋‹ต ๋ฉ”์„ธ์ง€ ๋“ฑ์ด ํฌํ•จ๋  ์ˆ˜ ์žˆ๋‹ค.
    • ๋”ฐ๋ผ์„œ ResponseEntity๋Š” client๊ฐ€ ๋ณด๋‚ด๋Š” ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์‘๋‹ต ๋‚ด์šฉ์„ ๊ทœ๊ฒฉ์— ๋งž๊ฒŒ ํ•œ๋ฒˆ ๊ฐ์‹ธ์ฃผ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.
    • ๊ฐ™์€ ์—ญํ• ๋กœ๋Š” @ResponseBody ์–ด๋…ธํ…Œ์ด์…˜์ด ์žˆ๋‹ค.
    • HttpEntity๋ฅผ ์ƒ์†๋ฐ›๊ณ  ์žˆ๋Š” ํด๋ž˜์Šค์ด๋‹ค.
  •  MultiValueMap
    • MultiValueMap์€ ํ‚ค ํ•˜๋‚˜์˜ ์—ฌ๋Ÿฌ๊ฐœ์˜ value๋ฅผ ๊ฐ€์ง€๊ฒŒ ํ•ด์ฃผ๋Š” map์ด๋‹ค. key-value ๊ฐ๊ฐ ํ•˜๋‚˜์”ฉ์ด ์Œ์œผ๋กœ ์ด๋ค„์ง€๋Š” map๊ณผ๋Š” ๋‹ค๋ฅด๋‹ค.
    • ์ค‘์š”ํ•œ ํŠน์ง•์ค‘์— ํ•˜๋‚˜๋Š” RestTemplate์˜ exchange ๋ฉ”์„œ๋“œ์˜ ์„ธ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ request์—๋Š” Hashmap์„ ์ง€์›ํ•˜์ง€ ์•Š์•„ ๋ฌด์กฐ๊ฑด MultiValueMap์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.
    • HTTP Request์‹œ์— URL์„ ์ „์†กํ•  ๋•Œ name="jennie"&name="lisa"&name="peter" ์™€ ๊ฐ™์ด ๊ฐ™์€ ํŒŒ๋ผ๋ฏธํ„ฐ์— ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๊ฐ’์ด ์ „์†ก๋˜๋Š” ์‚ฌ๋ก€๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

4) ๋งˆ์ง€๋ง‰์œผ๋กœ, ์ด ๊ตฌ๊ธ€ ์œ ์ € ์ •๋ณด๊ฐ€ ๋‹ด๊ธด JSON ๋ฌธ์ž์—ด์„ ํŒŒ์‹ฑํ•˜์—ฌ GoogleUser ๊ฐ์ฒด์— ๋‹ด์•„์ฃผ๋ฉด ๋œ๋‹ค.

  public GoogleUser getUserInfo(ResponseEntity<String> userInfoRes) throws JsonProcessingException{
        GoogleUser googleUser=objectMapper.readValue(userInfoRes.getBody(),GoogleUser.class);
        return googleUser;
    }

 

 

5. ์ด์ œ ๋งˆ์ง€๋ง‰์œผ๋กœ ๊ตฌ๊ธ€์—์„œ ๋ฐ›์•„์˜จ ์œ ์ € ์ •๋ณด๋ฅผ ์ด์šฉํ•ด ์ผ๋ จ์˜ ์ •๋ณด๊ฐ€ ๋‹ด๊ธด ๊ฐ์ฒด๋ฅผ ์ปจํŠธ๋กค๋Ÿฌ๋กœ ๋„˜๊ฒจ์ค€๋‹ค.

  • ์œ„์—์„œ ์–ป์€ GoogleUser๊ฐ์ฒด์— ๋‹ด๊ธด user_id๋ฅผ ์ถ”์ถœํ•œ๋‹ค.
  • ํ•ด๋‹น id๋ฅผ ์šฐ๋ฆฌ ์„œ๋ฒ„์˜ db์™€ ๊ฒ€์ฆํ•˜๊ณ , ํšŒ์› ๊ฐ€์ž…์ด ๋˜์–ด์žˆ์œผ๋ฉด ์•ž์œผ๋กœ ์ธ๊ฐ€ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด jwtToken์„ ๋ฐœ๊ธ‰ํ•œ๋‹ค.
    • jwtToken์„ ๋ฐœ๊ธ‰ํ•˜๋Š” jwtService ๊ฐœ๋ฐœ์€ ์ด์ „ ํฌ์ŠคํŒ…์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ํšŒ์›๊ฐ€์ž…์ด ๋˜์–ด์žˆ์ง€ ์•Š์œผ๋ฉด ํด๋ผ์ด์–ธํŠธ๋กœ ์˜ค๋ฅ˜๋ฅผ ์ „์†กํ•œ๋‹ค.
  • ์ด์ œ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ณด๋‚ด์ค„ GetSocialOauthRest ๊ฐ์ฒด๋ฅผ ๊ตฌ์„ฑํ•˜๋Š”๋ฐ, ๋‹ด๊ธด ๋‚ด์šฉ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
    • ํšŒ์› ์ธ๊ฐ€์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ jwtToken
    • ์œ ์ €์˜ ํšŒ์›๋ฒˆํ˜ธ
    • ์•ž์œผ๋กœ ๊ตฌ๊ธ€๊ณผ ํ†ต์‹ ํ• ๋•Œ ์‚ฌ์šฉํ•  accessToken
    • Token์˜ ํƒ€์ž… 
public GetSocialOAuthRes oAuthLogin(Constant.SocialLoginType socialLoginType, String code) throws IOException {

        switch (socialLoginType){
            case GOOGLE:{
                //๊ตฌ๊ธ€๋กœ ์ผํšŒ์„ฑ ์ฝ”๋“œ๋ฅผ ๋ณด๋‚ด ์•ก์„ธ์Šค ํ† ํฐ์ด ๋‹ด๊ธด ์‘๋‹ต๊ฐ์ฒด๋ฅผ ๋ฐ›์•„์˜ด
                ResponseEntity<String> accessTokenResponse= googleOauth.requestAccessToken(code);
               //์‘๋‹ต ๊ฐ์ฒด๊ฐ€ JSONํ˜•์‹์œผ๋กœ ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ, ์ด๋ฅผ deserializationํ•ด์„œ ์ž๋ฐ” ๊ฐ์ฒด์— ๋‹ด์„ ๊ฒƒ์ด๋‹ค.
               GoogleOAuthToken oAuthToken=googleOauth.getAccessToken(accessTokenResponse);
               
               //์•ก์„ธ์Šค ํ† ํฐ์„ ๋‹ค์‹œ ๊ตฌ๊ธ€๋กœ ๋ณด๋‚ด ๊ตฌ๊ธ€์— ์ €์žฅ๋œ ์‚ฌ์šฉ์ž ์ •๋ณด๊ฐ€ ๋‹ด๊ธด ์‘๋‹ต ๊ฐ์ฒด๋ฅผ ๋ฐ›์•„์˜จ๋‹ค.
                ResponseEntity<String> userInfoResponse=googleOauth.requestUserInfo(oAuthToken);
                //๋‹ค์‹œ JSON ํ˜•์‹์˜ ์‘๋‹ต ๊ฐ์ฒด๋ฅผ ์ž๋ฐ” ๊ฐ์ฒด๋กœ ์—ญ์ง๋ ฌํ™”ํ•œ๋‹ค.
                GoogleUser googleUser= googleOauth.getUserInfo(userInfoResponse);

                String user_id=googleUser.getEmail();
              
                //์šฐ๋ฆฌ ์„œ๋ฒ„์˜ db์™€ ๋Œ€์กฐํ•˜์—ฌ ํ•ด๋‹น user๊ฐ€ ์กด์žฌํ•˜๋Š” ์ง€ ํ™•์ธํ•œ๋‹ค.
                int user_num=accountProvider.getUserNum(user_id);
                
                if(user_num!=0){
                //์„œ๋ฒ„์— user๊ฐ€ ์กด์žฌํ•˜๋ฉด ์•ž์œผ๋กœ ํšŒ์› ์ธ๊ฐ€ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ jwtToken์„ ๋ฐœ๊ธ‰ํ•œ๋‹ค.
                String jwtToken=jwtService.createJwt(user_num,user_id);
                //์•ก์„ธ์Šค ํ† ํฐ๊ณผ jwtToken, ์ด์™ธ ์ •๋ณด๋“ค์ด ๋‹ด๊ธด ์ž๋ฐ” ๊ฐ์ฒด๋ฅผ ๋‹ค์‹œ ์ „์†กํ•œ๋‹ค.
                GetSocialOAuthRes getSocialOAuthRes=new GetSocialOAuthRes(jwtToken,user_num,oAuthToken.getAccess_token(),oAuthToken.getToken_type());
                return getSocialOAuthRes;
                }
                else {
                    throw new BaseException(BaseResponseStatus.ACCOUNT_DOESNT_EXISTS);
                }

            }
            default:{
                throw new IllegalArgumentException("์•Œ ์ˆ˜ ์—†๋Š” ์†Œ์…œ ๋กœ๊ทธ์ธ ํ˜•์‹์ž…๋‹ˆ๋‹ค.");
            }

        }

 

 

3. ์‹ค์ œ ์†Œ์…œ ๋กœ๊ทธ์ธ ํ”„๋กœ์„ธ์Šค

  1. localhost:9000/app/accounts/auth/google ๋กœ ์ ‘๊ทผ
  2. ๊ณง๋ฐ”๋กœ ์†Œ์…œ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋จ.

    3. ํ”„๋กœํ•„ ์„ ํƒ (๋กœ๊ทธ์ธ) ์ดํ›„์— ๋ฏธ๋ฆฌ ์ง€์ •ํ•ด๋‘” callback uri(๋ฏธ๋ฆฌ ๊ตฌ๊ธ€์— ๋“ฑ๋กํ•ด์•ผ ํ•จ)๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋˜๋ฉด์„œ ๊ตฌ๊ธ€์—์„œ ๋‚ด ์„œ๋ฒ„๋กœ ์ผํšŒ์„ฑ ์ ‘๊ทผ ์ฝ”๋“œ ๋ณด๋ƒ„

   4. ์ผํšŒ์„ฑ ์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ์„œ๋“œํŒŒํ‹ฐ๋กœ ๋ณด๋‚ด ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ์š”์ฒญํ•  ์ˆ˜ ์žˆ๋Š” ์•ก์„ธ์Šค ํ† ํฐ์„ response์— ๋‹ด์•„์˜ค๋„๋ก ํ•œ๋‹ค.

  5. ์ด ์•ก์„ธ์Šค ํ† ํฐ์„ ๋‹ค์‹œ ์„œ๋“œํŒŒํ‹ฐ๋กœ ๋ณด๋‚ด์„œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ๋ฐ›์•„์˜จ๋‹ค.

 6. ๋ฐ›์•„์˜จ ๊ตฌ๊ธ€ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ๋‚ด db์™€ ๋น„๊ตํ•˜์—ฌ JWT ํ† ํฐ์„ ๋ฐœ๊ธ‰ํ•˜๊ณ , ์ด๋ฅผ ํฌํ•จํ•ด ์•ก์„ธ์Šค ํ† ํฐ, ์œ ์ € ํšŒ์› ๋ฒˆํ˜ธ ๋“ฑ์ด ๋‹ด๊ธด ๊ฐ์ฒด๋ฅผ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์‘๋‹ต์œผ๋กœ ๋ณด๋‚ด์ค€๋‹ค.

 

 7.  ์‘๋‹ต ์™„๋ฃŒ! JSON ํ˜•ํƒœ๋กœ ์ž˜ ๋‚ด์šฉ์ด ๋Œ์•„์˜ค๋Š” ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

 

 

+) ์ƒ๊ฐ๋ณด๋‹ค ๊ณผ์ •์ด ๋งŽ์•„์„œ ๋ณต์žกํ–ˆ์—ˆ์ง€๋งŒ ๊ฐœ๋ฐœ์ด ์ž˜ ์™„๋ฃŒ๋˜์–ด์„œ ๊ธฐ์˜๋‹ค! ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ์ž˜ ์ฝ์–ด๋ณด๋ฉด์„œ ๊ฐœ๋ฐœํ•˜๋Š”๊ฒŒ ํ•„์ˆ˜์ ์ธ ๊ฒƒ ๊ฐ™๊ณ , ๋‹ค์Œ์—๋Š” Spring Security, JPA๋“ฑ์„ ๋„์ž…ํ•ด์„œ ๋” ์•ˆ์ „ํ•œ ์ธ์ฆ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋˜๋„๋ก ๋ฆฌํŒฉํ† ๋ง๋„ ํ•ด๋ณด๊ณ  ์‹ถ๋‹ค!

 

๐Ÿ™์ฐธ๊ณ ์ž๋ฃŒ 

https://developers.google.com/identity/protocols/oauth2/web-server#libraries

 

์›น ์„œ๋ฒ„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— OAuth 2.0 ์‚ฌ์šฉ  |  Google ID ํ”Œ๋žซํผ  |  Google Developers

์ด ํŽ˜์ด์ง€๋Š” Cloud Translation API๋ฅผ ํ†ตํ•ด ๋ฒˆ์—ญ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. Switch to English ์›น ์„œ๋ฒ„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— OAuth 2.0 ์‚ฌ์šฉ ์ด ๋ฌธ์„œ์—์„œ๋Š” ์›น ์„œ๋ฒ„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด Google API ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋˜๋Š” Google OAuth

developers.google.com

https://antdev.tistory.com/70?category=919963 

 

[Google Login API] ์†Œ์…œ ๋กœ๊ทธ์ธ ์š”์ฒญ Redirect ์ฒ˜๋ฆฌ (Spring Boot ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ๋ณด๋ฉด์„œ ๊ตฌํ˜„ํ•ด๋ณด๋Š” ๊ตฌ๊ธ€ ์†Œ์…œ

Spring Boot ํ™˜๊ฒฝ์—์„œ ๊ตฌ๊ธ€ ์†Œ์…œ ๋กœ๊ทธ์ธ API๋ฅผ REST ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ•˜๊ธฐ ์ด์ „๊ธ€ 2020/10/18 - [OAuth/Google Login API] - [Google Login API] ๊ฐœ๋ฐœํ™˜๊ฒฝ ๊ตฌ์„ฑ ๋ฐ Spring Boot ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ (Spring Boot ๋ ˆํผ๋Ÿฐ์Šค..

antdev.tistory.com

https://tecoble.techcourse.co.kr/post/2021-05-10-response-entity/

 

ResponseEntity - Spring Boot์—์„œ Response๋ฅผ ๋งŒ๋“ค์ž

์›น ์„œ๋น„์Šค์—์„œ๋Š” ๋งŽ์€ ์ •๋ณด๋ฅผ ์†ก์ˆ˜์‹ ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ฐ๊ฐ์˜ ๋‹ค๋ฅธ ์›น ์„œ๋น„์Šค๋“ค์ด ๋Œ€ํ™”ํ•˜๋ ค๋ฉด, ์„œ๋กœ ์ •ํ•ด์ง„ ์•ฝ์†์— ๋งž๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€๊ณตํ•ด์„œ ๋ณด๋‚ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๋ณด๋‚ด๋Š” ์š”์ฒญ ๋ฐ ๋ฐ์ดํ„ฐ์˜ ํ˜•์‹์„ ์šฐ๋ฆฌ๋Š” H

tecoble.techcourse.co.kr