๊ด€๋ฆฌ ๋ฉ”๋‰ด

๐Ÿ’ป๐Ÿ’ญ๐ŸŽง๐ŸŒ

[์›น ๊ฐœ๋ฐœ ํ”„๋กœ์ ํŠธ] 2. ๊ตฌ๊ธ€ ์†Œ์…œ ๋กœ๊ทธ์ธ ๊ตฌํ˜„ ๋ณธ๋ฌธ

์›น ๊ฐœ๋ฐœ ํ”„๋กœ์ ํŠธ

[์›น ๊ฐœ๋ฐœ ํ”„๋กœ์ ํŠธ] 2. ๊ตฌ๊ธ€ ์†Œ์…œ ๋กœ๊ทธ์ธ ๊ตฌํ˜„

adorableco 2024. 1. 5. 23:11
๋ฐ˜์‘ํ˜•

๊ตฌ๊ธ€ ๋กœ๊ทธ์ธ ๊ตฌํ˜„์€ ์•„๋ž˜์˜ ๋ธ”๋กœ๊ทธ๋ฅผ ๊ต‰์žฅํžˆ ๋งŽ์ด ์ฐธ๊ณ ํ–ˆ์Šต๋‹ˆ๋‹ค!!! ๋„ˆ๋ฌด๋„ˆ๋ฌด๋„ˆ๋ฌด๋„ˆ๋ฌด ๋„์›€์ด ๋งŽ์ด ๋์–ด์š” ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค...
https://antdev.tistory.com/71

 

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

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

antdev.tistory.com

 

 

 


๋„๋ฉ”์ธ ๊ณ„์ธต ๊ตฌ์กฐ ๋‚˜ํƒ€๋‚ด๋ ค๊ณ  ๋“œ๋””์–ด tree๋„ ์„ค์น˜ํ•˜์˜€๋‹ค! ์ด๋ฒˆ ์†Œ์…œ ๋กœ๊ทธ์ธ์„ ๊ตฌํ˜„ํ•  ๋•Œ ์˜ํ–ฅ์„ ๋ฐ›์€ ๋„๋ฉ”์ธ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

โ””โ”€โ”€ com
    โ””โ”€โ”€ example
        โ””โ”€โ”€ fit_friends
            โ”œโ”€โ”€ FitFriendsApplication.java
            โ”œโ”€โ”€ config
            โ”‚   โ””โ”€โ”€ auth
            โ”‚       โ”œโ”€โ”€ GoogleOAuth.java
            โ”‚       โ”œโ”€โ”€ SecurityConfig.java
            โ”‚       โ”œโ”€โ”€ SocialOAuth.java
            โ”‚       โ””โ”€โ”€ dto
            โ”‚           โ”œโ”€โ”€ GoogleRequestAccessTokenDto.java
            โ”‚           โ”œโ”€โ”€ OAuthAttributes.java
            โ”‚           โ””โ”€โ”€ SessionUser.java
            โ”œโ”€โ”€ controller
            โ”‚   โ”œโ”€โ”€ LoginController.java
            โ”‚   โ””โ”€โ”€ PostApiController.java

 

SocialOAuth.java

public interface SocialOAuth {
    String getOAuthRedirectUrl();

    String requestAccessToken(String code);
}

getOAuthRedirectUrl()

  • ๊ตฌ๊ธ€ ๋กœ๊ทธ์ธ ์ฐฝ์œผ๋กœ ์ด๋™ํ•˜๋Š” url์„ ๊ตฌ์„ฑํ•˜๋Š” ๋ฉ”์„œ๋“œ

requestAccessToken(String code)

  • ๊ตฌ๊ธ€ ๋กœ๊ทธ์ธ ์ฐฝ์—์„œ ๋กœ๊ทธ์ธ ํ›„ ๋ฐ›๋Š” code๋ฅผ ์ด์šฉํ•ด accessToken์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋„๋กํ•˜๋Š” url์„ ๊ตฌ์„ฑํ•˜๋Š” ๋ฉ”์„œ๋“œ

 

GoogleOAuth.java

  • SocialOAuth ์˜ ๊ตฌํ˜„์ฒด
package com.example.fit_friends.config.auth;

import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

@Component
@RequiredArgsConstructor
public class GoogleOAuth implements SocialOAuth{

    @Value("${google.client.id}")
    private String clientId;
    @Value("${google.redirect.uri}")
    private String redirectUri;

    @Value("${google.base.uri}")
    private String googleBaseUri;

    @Value("${google.client.secret}")
    private String clientSecret;

    @Value("${google.token_uri}")
    private String tokenUri;
    @Override
    public String getOAuthRedirectUrl() {
        Map<String,Object> params = new HashMap<>();
        params.put("client_id",clientId);
        params.put("response_type","code");
        params.put("redirect_uri",redirectUri);
        params.put("scope","profile");

        String paramsString = params.entrySet().stream()
                .map(x->x.getKey()+"="+x.getValue())
                .collect(Collectors.joining("&"));

        return googleBaseUri+"?"+paramsString;
    }

    @Override
    public String requestAccessToken(String code) {

        RestTemplate restTemplate = new RestTemplate();

        Map<String,Object> params = new HashMap<>();
        params.put("code",code);
        params.put("client_id",clientId);
        params.put("grant_type","authorization_code");
        params.put("response_type","code");
        params.put("redirect_uri",redirectUri);
        params.put("scope","profile");
        params.put("client_secret",clientSecret);

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

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

        return "๊ตฌ๊ธ€ ๋กœ๊ทธ์ธ ์š”์ฒญ ์ฒ˜๋ฆฌ ์‹คํŒจ";
    }
}

@Value() ๋กœ ๊ฐ€์ ธ์˜จ application.properties ์˜ ๋ณ€์ˆ˜๊ฐ’์ด null ๋กœ ๋œฌ๋‹ค๋ฉด,

  • ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ new ๋กœ ๊ฐ€์ ธ์˜จ๊ฑด ์•„๋‹Œ์ง€ ์ฒดํฌ
  • @Value() ๊ฐ€ properties์˜ ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๋Š”๊ฑด ํด๋ž˜์Šค๊ฐ€ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋˜๋Š” ์ˆœ๊ฐ„์ธ๋ฐ, ๋‹ค๋ฅธ ํด๋ž˜์Šค์—์„œ new ์—ฐ์‚ฐ์ž๋ฅผ ํ†ตํ•ด ์ด ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•ด๋ฒ„๋ฆฌ๋ฉด ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— @Value() ๋ฅผ ํ†ตํ•ด ๋ณ€์ˆ˜์— ๊ฐ’์ด ์ €์žฅ๋˜์ง€๋„ ์•Š๋Š” ๊ฒƒ์ด๋‹ค. โžก๏ธ ์ด๋Ÿฐ ์‹ค์ˆ˜๋ฅผ ํ•  ๋•Œ๋ฉด ๋ถ„๋ช… ์Šคํ”„๋ง์œผ๋กœ ๊ฐœ๋ฐœํ•˜๊ณ  ์žˆ๋Š”๋ฐ ์Šคํ”„๋ง์˜ ๊ธฐ๋Šฅ์„ ์ œ๋Œ€๋กœ ์“ฐ์ง€ ์•Š๊ณ  ์žˆ๋‹ค๋Š”๊ฒŒ ๋Š๊ปด์ง„๋‹ค..

 

getOAuthRedirectUrl()

์—์„œ ํ•„์š”ํ•œ request params์€ 4๊ฐ€์ง€์ด๋‹ค.

  • client_id, response_type, redirect_uri,scope
  • Map<> ์„ ์ด์šฉํ•ด params๋ฅผ ๊ตฌ์„ฑํ•œ๋‹ค. ์ค‘์š”ํ•œ ์ •๋ณด๋Š” application.properties ๋“ฑ์— ๋”ฐ๋กœ ๋นผ๋‘๊ณ  ๊บผ๋‚ด ์“ฐ๊ธฐ!!
String paramsString = params.entrySet().stream()
                .map(x->x.getKey()+"="+x.getValue())
                .collect(Collectors.joining("&"));
  • ๋žŒ๋‹ค์‹์œผ๋กœ ๊ตฌ์„ฑํ•˜๋‹ˆ ์ฝ”๋“œ๋„ ์งง์•„์ง€๊ณ  ์ข‹๋‹ค.....!

Map.entrySet() :Map์˜ Key-Value ์Œ์˜ ๋ชจ์Œ
Stream() : ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ์—ฐ์‚ฐ์„ ์ง€์›ํ•˜๋„๋ก ์ €์žฅ๋˜์–ด ์žˆ๋Š” ์š”์†Œ๋“ค์„ ์ถ”์ถœํ•˜์—ฌ ๋ฐ˜๋ณต์ ์ธ ์ฒ˜๋ฆฌ๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋Š” ๊ธฐ๋Šฅ

 

requestAccessToken(String code)

์—์„œ ํ•„์š”ํ•œ request params์€ 6๊ฐ€์ง€์ด๋‹ค.

  • code, client_id, grant_type, response_type, redirect_uri, scope, client_secret
  • redirect_uri ๋Š” ๋ชจ๋‘ ๊ตฌ๊ธ€ ํด๋ผ์šฐ๋“œ์—์„œ ๋ฏธ๋ฆฌ ์ž…๋ ฅํ•ด์ค€ uri๊ณผ ์ผ์น˜ํ•ด์•ผ ํ•œ๋‹ค.
 
restTemplate.postForEntity(String url, Object request, Class responseType)
  • POST ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ๊ฒฐ๊ณผ๋กœ ResponseEntity๋กœ ๋ฐ˜ํ™˜
    • url : ์š”์ฒญ์„ ๋ณด๋‚ผ ์„œ๋ฒ„์˜ url
    • request : POST ์š”์ฒญ ์‹œ ํ•จ๊ป˜ ๋ณด๋‚ผ ๊ฐ์ฒด
      • ์—ฌ๊ธฐ์—์„œ ๋‚˜๋Š” accessToken์„ ์–ป๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ params์„ ๋‹ด์•˜๋‹ค.
    • responseType : ์„œ๋ฒ„์˜ ์‘๋‹ต์„ ์–ด๋–ค ํ˜•ํƒœ๋กœ ๋ฐ›์„์ง€๋ฅผ ์ง€์ •ํ•˜๋Š” Class ๊ฐ์ฒด
    • POST ์š”์ฒญ ์‹œ์— ํ—ค๋”๊ฐ’๋„ ์ถ”๊ฐ€ํ•ด์•ผํ•œ๋‹ค๋ฉด?
      • HttpEntity ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์›๋ž˜ ๋ณด๋‚ด์•ผํ•˜๋Š” ๊ฐ์ฒด์™€, HttpHeaders ๊ฐ์ฒด๋ฅผ ํ•จ๊ป˜ ๋‹ด๋Š”๋‹ค.
        โœ… ์ด์™ธ์—๋„ ์„œ๋ฒ„์˜ ์‘๋‹ต์„ ๊ฐ์ฒด๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” PostforObject ๋‚˜ GET ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•˜๋Š” getForEntity ๋“ฑ ๋‹ค์–‘ํ•˜๊ฒŒ ์กด์žฌํ•œ๋‹ค.

LoginController.java

public class LoginController{

    @Autowired
    private final SocialOAuth socialOAuth;
    private final HttpServletResponse response;

    @GetMapping("/api/login")
    public void loginGoogle() throws Exception{

        response.sendRedirect(socialOAuth.getOAuthRedirectUrl());
    }

    @GetMapping("/login/oauth2/code/google")
    public String requestToken(@RequestParam(name="code") String code) throws Exception{
        return socialOAuth.requestAccessToken(code);
    }
  • ์‚ฌ์‹ค ์ฒ˜์Œ์— ๊ฐ€์žฅ ํ—ค๋งธ๋˜ ๋ถ€๋ถ„์ด๋‹ค.. ๋กœ๊ทธ์ธ ์š”์ฒญ์„ ํ•˜๊ณ  ๋ฆฌ๋””๋ ‰ํŠธ๋˜๋ฉด ๊ทธ๊ฑธ ๋‹ค์‹œ GetMapping ํ•˜๊ณ  ๊ทธ ๋‹ค์Œ์—” ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ•˜์ง€..? ๋ผ๋Š” ์ƒ๊ฐ์—์„œ ๋ง‰ํ˜€์„œ ์ง„์งœ ํ•œ์ฐธ์„ ํ—ค๋งธ๋‹ค. ๊ณ„์† controller์˜ ํ•œ ๋ฉ”์„œ๋“œ ๋‚ด์—์„œ code ๋ฐ›์€๊ฑธ ๋‹ค์‹œ accessToken ์„ ๋ฐ›๊ธฐ ์œ„ํ•ด ์ฃผ์†Œ๋ฅผ ๋ฆฌ๋””๋ ‰ํŠธํ•˜๊ณ .. ๋ณต์žกํ•˜๊ฒŒ ์ƒ๊ฐํ–ˆ๋Š”๋ฐ ๊ทธ๋ƒฅ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ๊ฐ ๋‹ค ๋‚˜๋ˆ„๋ฉด ์ƒ๊ฐํ•˜๊ธฐ๋„ ํ›จ์”ฌ ์‰ฝ๋‹ค!

 

๋‹ค์Œ ํ•  ์ผ

  • ๊ตฌ๊ธ€ ๋กœ๊ทธ์ธ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋„๋ก User ๋„๋ฉ”์ธ ์ˆ˜์ •
  • User ๋„๋ฉ”์ธ๊ณผ ๊ด€๊ณ„๊ฐ€ ์žˆ๋Š” ์—ฌ๋Ÿฌ ๋„๋ฉ”์ธ ๋”๋Ÿฌ ์ˆ˜์ •(...)
  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋„ ์ˆ˜์ •ํ•ด์•ผ ํ•˜์ง€ ์•Š์„๊นŒ.
๋ฐ˜์‘ํ˜•