Darren's Devlog

[OAuth 2.0] 스프링부트로 Google 로그인 구현해보기 -2 본문

Spring

[OAuth 2.0] 스프링부트로 Google 로그인 구현해보기 -2

Darren Gwon 2023. 1. 14. 00:26
반응형
 

[OAuth 2.0] OAuth 개념과 구글 OAuth 세팅 및 로그인 스프링부트로 구현 해보기 -1

안녕하세요. 이번 게시글에서는 OAuth 2.0에 대한 간략한 개념과 스프링부트 환경에서 직접 구현해보는 단계까지 다뤄보도록 하겠습니다. OAuth, Open Authorization 정의 OAuth는 인터넷 사용자들이 비밀

darrenlog.tistory.com

이번 게시글은 1편에 이어 스프링 부트를 활용하여 유저의 이메일 정보를 받아오는 코드를 작성해 보도록 하겠습니다.


1. Authorization Code 발급

가장 먼저 해야하는 Authoriztion code 발급부터 테스트해보도록 하겠습니다.

https://accounts.google.com/o/oauth2/auth?client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&response_type=code&scope=https://www.googleapis.com/auth/userinfo.emailhttps://www.googleapis.com/auth/userinfo.profile

유저가 위 페이지에서 구글 로그인을 마치고나면 redirect_uri에 Authorization code를 응답해 줍니다.

일단 Authorization code를 콘솔에 출력하는 것부터 진행해 보겠습니다.


패키지 구조는 간단하게 구성하였습니다.

 

application.yml

oauth2:
  google:
    client-id: 클라이언트ID
    client-secret: 클라이언트SECRET
    redirect-uri: 리디렉션URI
    token-uri: https://oauth2.googleapis.com/token
    resource-uri: https://www.googleapis.com/oauth2/v2/userinfo
  kakao:
    client-id: 클라이언트ID
    client-secret: 클라이언트SECRET
    redirect-uri: 리디렉션URI
    token-uri: 엑세스토큰URI
    resource-uri: 리소스URI

 

컨트롤러

 

컨트롤러 URL Mapping은 Google OAuth API 설정 시 등록했던 리디렉션 URI와 동일하게 해 주세요.

@RestController
@RequestMapping(value = "/login/oauth2", produces = "application/json")
public class LoginController {

    LoginService  loginService;

    public LoginController(LoginService loginService) {
        this.loginService = loginService;
    }

    @GetMapping("/code/{registrationId}")
    public void googleLogin(@RequestParam String code, @PathVariable String registrationId) {
        loginService.socialLogin(code, registrationId);
    }
}

 

서비스

@Service
public class LoginService {
    public void socialLogin(String code, String registrationId) {
        System.out.println("code = " + code);
        System.out.println("registrationId = " + registrationId);
    }
}

구글 로그인 후에 콘솔에 위에  사진처럼 잘 출력되신다면 성공입니다.


2. Access Token 발급

발급받은 Authorization code를 통해 Access Token을 발급받아보겠습니다.

 

서비스

@Service
public class LoginService {

    private final Environment env;
    private final RestTemplate restTemplate = new RestTemplate();
    
    public LoginService(Environment env) {
        this.env = env;
    }
    public void socialLogin(String code, String registrationId) {
        String accessToken = getAccessToken(code, registrationId);
        System.out.println("accessToken = " + accessToken);
    }

    private String getAccessToken(String authorizationCode, String registrationId) {
        String clientId = env.getProperty("oauth2." + registrationId + ".client-id");
        String clientSecret = env.getProperty("oauth2." + registrationId + ".client-secret");
        String redirectUri = env.getProperty("oauth2." + registrationId + ".redirect-uri");
        String tokenUri = env.getProperty("oauth2." + registrationId + ".token-uri");

        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("code", authorizationCode);
        params.add("client_id", clientId);
        params.add("client_secret", clientSecret);
        params.add("redirect_uri", redirectUri);
        params.add("grant_type", "authorization_code");

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        HttpEntity entity = new HttpEntity(params, headers);

        ResponseEntity<JsonNode> responseNode = restTemplate.exchange(tokenUri, HttpMethod.POST, entity, JsonNode.class);
        JsonNode accessTokenNode = responseNode.getBody();
        return accessTokenNode.get("access_token").asText();
    }
}

콘솔에 다음과 같이 출력되었으면 accessToken까지 발급하는 데에 성공하셨습니다.


3. Resource Server에서 유저정보 받기

이제 마지막 단계입니다.

OAuth 개념에 Resource Server라는 것이 있는데

유저 정보를 안전하게 저장하고 있는 서버라고 생각하시면 됩니다.

 

서비스

@Service
public class LoginService {

    private final Environment env;
    private final RestTemplate restTemplate = new RestTemplate();

    public LoginService(Environment env) {
        this.env = env;
    }
    public void socialLogin(String code, String registrationId) {
        String accessToken = getAccessToken(code, registrationId);
        JsonNode userResourceNode = getUserResource(accessToken, registrationId);
        System.out.println("userResourceNode = " + userResourceNode);

        String id = userResourceNode.get("id").asText();
        String email = userResourceNode.get("email").asText();
        String nickname = userResourceNode.get("name").asText();
        System.out.println("id = " + id);
        System.out.println("email = " + email);
        System.out.println("nickname = " + nickname);
    }

    private String getAccessToken(String authorizationCode, String registrationId) {
        String clientId = env.getProperty("oauth2." + registrationId + ".client-id");
        String clientSecret = env.getProperty("oauth2." + registrationId + ".client-secret");
        String redirectUri = env.getProperty("oauth2." + registrationId + ".redirect-uri");
        String tokenUri = env.getProperty("oauth2." + registrationId + ".token-uri");

        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("code", authorizationCode);
        params.add("client_id", clientId);
        params.add("client_secret", clientSecret);
        params.add("redirect_uri", redirectUri);
        params.add("grant_type", "authorization_code");

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        HttpEntity entity = new HttpEntity(params, headers);

        ResponseEntity<JsonNode> responseNode = restTemplate.exchange(tokenUri, HttpMethod.POST, entity, JsonNode.class);
        JsonNode accessTokenNode = responseNode.getBody();
        return accessTokenNode.get("access_token").asText();
    }

    private JsonNode getUserResource(String accessToken, String registrationId) {
        String resourceUri = env.getProperty("oauth2."+registrationId+".resource-uri");

        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", "Bearer " + accessToken);
        HttpEntity entity = new HttpEntity(headers);
        return restTemplate.exchange(resourceUri, HttpMethod.GET, entity, JsonNode.class).getBody();
    }
}

콘솔에 위처럼 값이 출력되면 구글 OAuth2.0 로그인 부분 구현에 성공하셨습니다.

이제 발급받은 email 정보를 통해 각자 서비스 정책에 맞는 회원가입 로직을 작성하시면 됩니다.

 

최종 코드는 깃헙에 공유해놓았습니다.

 

GitHub - darren-gwon/springboot_oauth_example: springboot_oauth_example

springboot_oauth_example. Contribute to darren-gwon/springboot_oauth_example development by creating an account on GitHub.

github.com

 

반응형
Comments