๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๊ฐœ์ธ ๊ณต๋ถ€/WEB-Spring,SpringBoot

[TIL] Spring Security, OAuth2 Client ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์“ฐ์ง€ ์•Š๊ณ  ๊ตฌ๊ธ€ OAuth ํšŒ์›๊ฐ€์ž… ๊ตฌํ˜„ํ•˜๊ธฐ

by syLim___ 2024. 11. 17.
728x90

โœ… ๊ฐœ๋ฐœํ™˜๊ฒฝ

SpringBoot 3.2.11, Gradle

JDK 17

 

์ตœ๊ทผ ๋ฉฐ์น ๊ฐ„ ๊ฐ•์˜๋ฅผ ๋“ค์œผ๋ฉด์„œ Spring Security์™€ OAuth2 Client ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ™œ์šฉํ•ด ๊ตฌ๊ธ€, ํŽ˜์ด์Šค๋ถ, ๋„ค์ด๋ฒ„ OAuth ํšŒ์›๊ฐ€์ž…๊ณผ ๋กœ๊ทธ์ธ์„ ๊ตฌํ˜„ํ•˜๋Š” ์—ฐ์Šต์„ ํ•ด๋ณด์•˜๋‹ค.

๋งˆ์นจ ์š”์ฆ˜ ์ง„ํ–‰์ค‘์ธ ํ”„๋กœ์ ํŠธ๊ฐ€ ์ด์ œ ๋ง‰ ๊ตฌํ˜„ ๋‹จ๊ณ„์— ์ง„์ž…ํ•ด์„œ, ์—ฌ๊ธฐ์— ๊ตฌ๊ธ€ OAuth ๋กœ๊ทธ์ธ๊ณผ ํšŒ์›๊ฐ€์ž…๋งŒ ์ ์šฉํ•ด๋ณด๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์•„์„œ ๋‚ด๊ฐ€ ํ•œ ๋ฒˆ ์ ์šฉํ•ด๋ณด๊ฒ ๋‹ค๊ณ  ํ–ˆ๋‹ค.

 

โœ… ๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ ํ”„๋กœ์ ํŠธ๋Š” ๊ฐ•์˜ ์† ํ”„๋กœ์ ํŠธ์™€๋Š” ๊ตฌ์กฐ์ ์ธ ์ฐจ์ด๊ฐ€ ์žˆ์—ˆ๋‹ค.

๊ฐ•์˜ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ๋กœ๊ทธ์ธ๊ณผ ํšŒ์›๊ฐ€์ž…์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๊ฐ€ ๋”ฐ๋กœ ์žˆ์ง€ ์•Š๊ณ ,

ํ”„๋ก ํŠธ ์„œ๋ฒ„ ํ•˜๋‚˜๋ฅผ ๋‘๊ณ  Spring Security๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ๊ทธ์ธ๊ณผ ํšŒ์›๊ฐ€์ž… ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜์˜€๋‹ค.

 

๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ ํ”„๋กœ์ ํŠธ๋Š” ํ”„๋ก ํŠธ ์„œ๋ฒ„์™€ ๋ฐฑ ์„œ๋ฒ„๊ฐ€ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์—ˆ๋‹ค.

ํ”„๋ก ํŠธ ์„œ๋ฒ„๋Š” nginx๋กœ ๋˜์–ด ์žˆ๊ณ , ์‚ฌ์šฉ์ž๊ฐ€ ํšŒ์›๊ฐ€์ž… ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด ์ด ์š”์ฒญ์€ ๊ฒŒ์ดํŠธ์›จ์ด๋ฅผ ๊ฑฐ์ณ์„œ

user-service๋ผ๋Š” ๋ฐฑ์—”๋“œ ์„œ๋ฒ„์—์„œ ์ฒ˜๋ฆฌ๋˜๋„๋ก ์„ค๊ณ„๋˜์–ด ์žˆ์—ˆ๋‹ค.

 

๊ทธ๋ž˜๋„ OAuth ์ธ์ฆ์„ ํ†ตํ•ด ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์›๋ฆฌ๋Š” ์•Œ๊ณ  ์žˆ์œผ๋‹ˆ ์–ด๋–ป๊ฒŒ๋“  ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๊ฒ ์ง€ ์‹ถ์–ด์„œ

๋งจ๋•…์— ํ—ค๋”ฉํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„์— ๋„์ „ํ•ด๋ณด์•˜๋‹ค!

 

 

๊ตฌํ˜„ ๊ณผ์ •์— ๋ฐฐ์šด ์ ๋„ ๋งŽ์€ ๊ฒƒ ๊ฐ™์•„์„œ ์ผ๊ธฐ์ฒ˜๋Ÿผ ์จ๋ณด๋ ค๊ณ  ํ•œ๋‹ค.

 

๊ฐ€๋…์„ฑ ์•ˆ ์ข‹์Œ ์ฃผ์˜, ๋‚˜๋งŒ ์•Œ์•„๋ณผ ์ˆ˜ ์žˆ์Œ ์ฃผ์˜...!

 

 

โœ… ์šฐ์„ ์€ ์š”์ฒญ๊ณผ ์‘๋‹ต์ด ์™”๋‹ค๊ฐ”๋‹ค ํ•˜๋Š” ๊ฒƒ์„ ์ง์ ‘ ํ™•์ธํ•˜๊ณ  ์‹ถ์–ด์„œ
SpringSecurity์™€ OAuth2 Client ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๊ณ  ์Œฉ์œผ๋กœ ๊ตฌํ˜„์„ ํ•ด๋ณด์•˜๋‹ค.

 

 

์•„๋ž˜๋Š” ์™„์„ฑ๋œ ์ฝ”๋“œ์ด๋‹ค.

 

๐Ÿ“Œ front-service (localhost:8080)

 

loginForm.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Google OAuth Login</title>
</head>
<body>
<h1>Login with Google</h1>
<a id="google-signup-button" href="#">
    <button>Google ๊ฐ„ํŽธ ํšŒ์›๊ฐ€์ž…ํ•˜๊ธฐ</button>
</a>

<script>
    fetch('http://localhost:8090/oauth_state', { method: 'POST', credentials: 'include' })
        .then(response => response.text())
        .then(state => {
            const googleAuthUrl = `https://accounts.google.com/o/oauth2/v2/auth?` +
                `client_id=668863934871-v4070e9ugtjvb34us0irg2u1muu46ra2.apps.googleusercontent.com` +
                `&redirect_uri=http://localhost:8090/asdf` +
                `&response_type=code` +
                `&scope=openid%20profile%20email` +
                `&state=${state}`;
            document.getElementById('google-signup-button').href = googleAuthUrl;
        });
</script>
<script>
    const urlParams = new URLSearchParams(window.location.search);
    const status = urlParams.get('status');
    const message = urlParams.get('message');

    if (status === 'success') {
        alert('ํšŒ์›๊ฐ€์ž… ์™„๋ฃŒ!');
    } else if (status === 'error') {
        if(message === 'alreadyExists') {
            alert('์ด๋ฏธ ๊ฐ€์ž…๋œ ํšŒ์›์ž…๋‹ˆ๋‹ค.');
        } else {
            alert('ํšŒ์›๊ฐ€์ž…์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.');
        }
    }
</script>
</body>
</html>

 

์šฐ์„  ํ”„๋ก ํŠธ์—”๋“œ์—์„œ "Google ๊ฐ„ํŽธ ํšŒ์›๊ฐ€์ž…ํ•˜๊ธฐ" ๋ฒ„ํŠผ์„ ํด๋ฆญํ•œ๋‹ค.
์ด ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ๊ตฌ๊ธ€ OAuth ์„œ๋ฒ„์˜ ์‚ฌ์šฉ์ž ์ธ์ฆ ํŽ˜์ด์ง€๋กœ GET ์š”์ฒญ์„ ๋ณด๋‚ด๊ฒŒ ๋œ๋‹ค.

์ด ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ URL์€ ๋™์ ์œผ๋กœ ์ƒ์„ฑ๋œ๋‹ค.

 

URL์ด ๋™์ ์œผ๋กœ ์ƒ์„ฑ๋˜๋Š” ์ด์œ ๋Š” ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ์ค‘ state ๊ฐ’์„ user-service์—์„œ ๋ฐ›์•„์™€์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
state ๊ฐ’์€ CSRF ๊ณต๊ฒฉ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•œ ์šฉ๋„๋กœ ์‚ฌ์šฉ๋œ๋‹ค.

 

๊ตฌ๊ธ€ OAuth ์„œ๋ฒ„์—์„œ ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ์„ ์™„๋ฃŒํ•˜๋ฉด,

์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ์ค‘ redirect_uri๋กœ ์ง€์ •ํ•œ ์—”๋“œํฌ์ธํŠธ์—์„œ ์‘๋‹ต์„ ๋ฐ›์•„๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์—”๋“œํฌ์ธํŠธ๋Š” ํ…Œ์ŠคํŠธ์šฉ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ž„์˜๋กœ asdf๋ผ๊ณ  ์„ค์ •ํ–ˆ๋‹ค.

์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ response_type=code๋กœ ์ง€์ •ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์‘๋‹ต์œผ๋กœ ์ฝ”๋“œ๊ฐ€ ์˜ฌ ๊ฒƒ์ด๋‹ค.

 

 

๐Ÿ“Œ user-service (localhost:8090)

 

1. state๊ฐ’ ๋™์  ์ƒ์„ฑํ•˜์—ฌ front-service์— ๋ณด๋‚ด์ฃผ๋Š” ๋ถ€๋ถ„

SignupController.java

	@PostMapping("/oauth_state")
    public ResponseEntity<String> generateState(HttpSession session) {
        String state = UUID.randomUUID().toString();
        session.setAttribute(KEY_OAUTH_STATE, state);
        return ResponseEntity.ok(state);
    }

 

์šฐ์„  state๊ฐ’์„ ๋™์ ์œผ๋กœ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ์—”๋“œํฌ์ธํŠธ๋ฅผ ๊ตฌํ˜„ํ•˜์˜€๋‹ค.

front-service์—์„œ ํ•ด๋‹น ์—”๋“œํฌ์ธํŠธ๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด,

user-service์—์„œ๋Š” uuid๋ฅผ ๋žœ๋ค์œผ๋กœ ์ƒ์„ฑํ•˜์—ฌ ์„ธ์…˜์— ์ €์žฅํ•ด๋‘๊ณ , front-service์—๊ฒŒ ์ด uuid๋ฅผ ๋ณด๋‚ด์ค€๋‹ค.

 

2. ๊ตฌ๊ธ€ OAuth ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ์ฝ”๋“œ ์‘๋‹ต๋ฐ›๋Š” ๋ถ€๋ถ„

SignupController.java

@GetMapping("/asdf")
    @CrossOrigin(origins = "http://localhost:8080", allowCredentials = "true")
    public ResponseEntity<String> handleGoogleOAuthCallback(@RequestParam MultiValueMap<String, String> params,
                                                            HttpSession session,
                                                            HttpServletResponse httpResponse) {
        log.info("Google Oauth ์ธ์ฆ ์™„๋ฃŒ, ์‘๋‹ต ํŒŒ๋ผ๋ฏธํ„ฐ:");
        params.forEach((key, value) -> log.info(key + " = " + value));

        String originalState = (String) session.getAttribute(KEY_OAUTH_STATE);
        log.info("state from front service={}, originalState={}", params.get("state"), originalState);
        if (!params.get("state").contains(originalState)) {
            throw new IllegalStateException("Invalid state parameter");
        }
        
        ...
        
    }

๊ทธ๋ฆฌ๊ณ  ์‚ฌ์šฉ์ž๊ฐ€ ํ”„๋ก ํŠธ ์„œ๋ฒ„๋ฅผ ํ†ตํ•ด OAuth ์ธ์ฆ ์„œ๋ฒ„๋กœ ์ด๋™ํ•˜์—ฌ ์ธ์ฆ์„ ์™„๋ฃŒํ•˜๊ณ  ๋‚˜๋ฉด,

ํ•ด๋‹น ์—”๋“œํฌ์ธํŠธ์—์„œ ์‘๋‹ต์„ ๋ฐ›์•„๋ณผ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

 

ํ˜„์žฌ user-service์˜ ์„ธ์…˜์— ์žˆ๋Š” state๊ฐ’์€ front-service์˜ ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ์˜ state๊ฐ’๊ณผ ๋™์ผํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— (csrf ๋ฐฉ์ง€)

๋งŒ์•ฝ state ๊ฐ’์ด ์ผ์น˜ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ์ฃผ์—ˆ๋‹ค.

 

์—ฌ๊ธฐ๊นŒ์ง€ ์ง„ํ–‰์ด ์™„๋ฃŒ๋˜๋ฉด, ์•„๋ž˜์™€ ๊ฐ™์€ ๋กœ๊ทธ๊ฐ€ ์ฐํžŒ๋‹ค.

 

 

3. ๊ตฌ๊ธ€ OAuth ์„œ๋ฒ„์—๊ฒŒ ์•ก์„ธ์Šค ํ† ํฐ ์š”์ฒญํ•˜๊ณ  ์‘๋‹ต๋ฐ›๋Š” ๋ถ€๋ถ„

 

๊ทธ ๋‹ค์Œ์€ ํ•ด๋‹น ์ฝ”๋“œ ๊ตฌ๊ธ€ OAuth ์„œ๋ฒ„์— ์ „์†กํ•˜์—ฌ,

์‚ฌ์šฉ์ž ์ •๋ณด์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ๋Š” ์•ก์„ธ์Šค ํ† ํฐ์„ ์‘๋‹ต๋ฐ›์•„์•ผํ•œ๋‹ค.

 

...
private static final String GRANT_TYPE = "authorization_code";
private static final String TOKEN_URL = "https://oauth2.googleapis.com/token";
...

@GetMapping("/asdf")
    @CrossOrigin(origins = "http://localhost:8080", allowCredentials = "true")
    public ResponseEntity<String> handleGoogleOAuthCallback(@RequestParam MultiValueMap<String, String> params,
                                                            HttpSession session,
                                                            HttpServletResponse httpResponse) {
        
        ...

        String code = params.getFirst("code");
        String clientId = {ํด๋ผ์ด์–ธํŠธID};
        String clientSecret = {ํด๋ผ์ด์–ธํŠธ ๋ณด์•ˆ ๋น„๋ฐ€๋ฒˆํ˜ธ};
        String redirectUri = "http://localhost:8090/asdf";

        // Google OAuth ์„œ๋ฒ„์— Access token ์š”์ฒญ
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        String body = "code=" + URLEncoder.encode(code, StandardCharsets.UTF_8) +
                "&client_id=" + URLEncoder.encode(clientId, StandardCharsets.UTF_8) +
                "&client_secret=" + URLEncoder.encode(clientSecret, StandardCharsets.UTF_8) +
                "&redirect_uri=" + URLEncoder.encode(redirectUri, StandardCharsets.UTF_8) +
                "&grant_type=" + URLEncoder.encode(GRANT_TYPE, StandardCharsets.UTF_8);

        HttpEntity<String> entity = new HttpEntity<>(body, headers);
        try {
            log.info("Google oauth ์„œ๋ฒ„์— post ์š”์ฒญ ์ „์†ก : {}", entity);
            ResponseEntity<String> response = restTemplate.postForEntity(TOKEN_URL, entity, String.class);
            log.info("์‘๋‹ต status code: {}", response.getStatusCode());
            log.info("์‘๋‹ต body: {}", response.getBody());


		...
        
}

 

RestTemplate์„ ์ด์šฉํ•ด์„œ ๊ตฌ๊ธ€ OAuth ์„œ๋ฒ„์˜ /token ์—”๋“œํฌ์ธํŠธ๋กœ POST์š”์ฒญ์„ ๋ณด๋ƒˆ๋‹ค.

 

์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ์—๋Š” ์š”์ฒญ ๋ฐ”๋””์— ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ code, client_id, client_secret, redirect_uri, grant_type์„ ๋ฐ˜๋“œ์‹œ ๋ช…์‹œํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

์ด๋•Œ code๋Š” ์œ„์—์„œ ์‘๋‹ต๋ฐ›์€ code๋ฅผ ๊ทธ๋Œ€๋กœ ๋„ฃ์–ด์ฃผ๋ฉด ๋œ๋‹ค.

redirect_uri๋Š” ๋ฐ˜๋“œ์‹œ ๋งจ ์ฒ˜์Œ front-service์—์„œ ์‚ฌ์šฉ์ž ์ธ์ฆ์„ ์œ„ํ•œ ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ ์ ์–ด์ค€ uri๋ฅผ ๊ทธ๋Œ€๋กœ ์ ์–ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

    (๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด invalid_grant๋‚˜ redirect_uri_mismatch๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ์ด๊ฒƒ ๋•Œ๋ฌธ์— ๊ฝค ๋งŽ์ด ๊ณ ์ƒํ–ˆ๋‹ค..)

๊ทธ๋ฆฌ๊ณ  grant_type์€ "authorization_code" ๊ณ ์ •์ด๋‹ค. ๋ฌด์กฐ๊ฑด ์ด๋ ‡๊ฒŒ ์ ์–ด์ฃผ์–ด์•ผ ํ•œ๋‹ค๊ณ  ํ•œ๋‹ค.

 

์—ฌ๊ธฐ๊นŒ์ง€ ์ง„ํ–‰๋˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๋กœ๊ทธ๊ฐ€ ์ฐํžŒ๋‹ค.

 

 

4. ๊ตฌ๊ธ€ ์‚ฌ์šฉ์ž ์ •๋ณด api์—๊ฒŒ ์•ก์„ธ์Šค ํ† ํฐ์„ ๋ณด๋‚ด์„œ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ถ€๋ถ„

...
private static final String USER_INFO_URL = "https://www.googleapis.com/oauth2/v3/userinfo";
...

@GetMapping("/asdf")
    @CrossOrigin(origins = "http://localhost:8080", allowCredentials = "true")
    public ResponseEntity<String> handleGoogleOAuthCallback(@RequestParam MultiValueMap<String, String> params,
                                                            HttpSession session,
                                                            HttpServletResponse httpResponse) {
        ...

            String accessToken = String.valueOf(objectMapper.readTree(response.getBody()).get("access_token"));

            // ์‚ฌ์šฉ์ž ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
            restTemplate = new RestTemplate();
            HttpHeaders userInfoHeaders = new HttpHeaders();
            userInfoHeaders.setBearerAuth(accessToken);
            HttpEntity<String> userInfoEntity = new HttpEntity<>(userInfoHeaders);

            log.info("Google user info api ์— get ์š”์ฒญ ์ „์†ก: {}", userInfoEntity);
            ResponseEntity<String> userInfoResponse = restTemplate.exchange(USER_INFO_URL, HttpMethod.GET, userInfoEntity, String.class);
            log.info("์‘๋‹ต Status Code: {}", userInfoResponse.getStatusCode());
            log.info("์‘๋‹ต Body: {}", userInfoResponse.getBody());

            JsonNode userInfo = objectMapper.readTree(userInfoResponse.getBody());
            String sub = userInfo.get("sub").asText();
            if (signupService.findUserByUserId("google_" + sub) == null) {
                String userId = signupService.signUp(userInfo);
                String message = URLEncoder.encode("ํšŒ์›๊ฐ€์ž… ์„ฑ๊ณต!");
                String redirectUrl = "http://localhost:8080/?status=success&message=" + message;
                if (!httpResponse.isCommitted()) {
                    httpResponse.sendRedirect(redirectUrl);
                }
            }
            
            ...

 

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํšŒ์›์˜ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

sub๋Š” ํšŒ์›์˜ pk, id๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค๊ณ  ํ•œ๋‹ค.

 

์‘๋‹ต์ด ์ •์ƒ์ ์œผ๋กœ ์™”๋‹ค๋ฉด ์œ„์™€ ๊ฐ™์€ ๋กœ๊ทธ๊ฐ€ ์ฐํžŒ๋‹ค.

 

5. ํšŒ์›๊ฐ€์ž… ๋กœ์ง ์ˆ˜ํ–‰ ํ›„ front-service์— ์‘๋‹ต ๋ณด๋‚ด๊ธฐ

์ด์ œ ์ด ํšŒ์›์„ ์šฐ๋ฆฌ ์„œ๋ฒ„์˜ DB์— ์ž„์˜๋กœ ๊ฐ€์ž…์‹œํ‚ค๋ฉด ๋œ๋‹ค.

 

๋‚˜๋Š” ์•„์ด๋””=google_{sub}, ๋น„๋ฐ€๋ฒˆํ˜ธ=asdf_{sub} ๋กœ ์„ค์ •ํ•˜์˜€๊ณ ,

name๊ณผ email ํ•„๋“œ์—๋Š” ๊ตฌ๊ธ€ ์‚ฌ์šฉ์ž api๋กœ๋ถ€ํ„ฐ ๋ฐ›์•„์˜จ ์‚ฌ์šฉ์ž์˜ name๊ณผ email ์ •๋ณด๋ฅผ ๋„ฃ์–ด์„œ ํšŒ์›๊ฐ€์ž…์„ ์‹œ์ผฐ๋‹ค.

 

๊ตฌ๊ธ€ OAuth๋ฅผ ํ†ตํ•ด ๊ฐ€์ž…ํ•œ ํšŒ์›์ด๋ผ๋Š” ๊ฒƒ์„ ํ‘œ์‹œํ•ด์ฃผ๊ธฐ ์œ„ํ•ด์„œ User entity์— provider๋ผ๋Š” ํ•„๋“œ๋„ ๋‘์—ˆ๋‹ค.

 

๋กœ์ปฌ ํ…Œ์ŠคํŠธ์šฉ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ด๋ ‡๊ฒŒ ํšŒ์›์ด ์ €์žฅ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

๊ฐ€์ž…์ด ์™„๋ฃŒ๋˜๋ฉด front-service๋กœ redirect์‘๋‹ต์„ ๋ณด๋‚ธ๋‹ค.

์‘๋‹ต url ํŒŒ๋ผ๋ฏธํ„ฐ์˜ status ๊ฐ’์— ๋”ฐ๋ผ ๊ฐ๊ฐ ๋‹ค๋ฅธ ์•Œ๋ฆผ์ฐฝ์ด ๋œจ๋ฉด์„œ, index ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด์—‘ํŠธ ๋˜๋„๋ก ์„ค์ •ํ•ด์ฃผ์—ˆ๋‹ค.

 

 

์ด์ œ, OAuth2 Client ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ Spring Security๋ฅผ ๋„์ž…ํ•ด๋ณด๋ ค๊ณ  ํ•œ๋‹ค!

 

 

์ฐธ๊ณ ๋กœ ๊ตฌํ˜„ ์ค‘๊ฐ„์— ํด๋ผ์ด์–ธํŠธ ID๋ฅผ ์ž˜๋ชป ์ ์–ด์„œ ํ•œ์‹œ๊ฐ„์ •๋„ 401์˜ ๋Šช์— ๋น ์กŒ์—ˆ๋‹ค.

์ธ์„ญ์ด์˜ค๋น ๊ฐ€ ํด๋ผ์ด์–ธํŠธID๊ฐ€ ์ž˜๋ชป๋œ ๊ฑธ ์ฐพ์•„์คฌ๋Š”๋ฐ ์ง„์งœ ๋„ˆ๋ฌด ๊ณ ๋งˆ์› ๋‹ค.

 

โœ… References

- https://developers.google.com/identity/protocols/oauth2?hl=ko

- https://developers.google.com/identity/protocols/oauth2/web-server?hl=ko#httprest

- https://cloud.google.com/apigee/docs/api-platform/reference/policies/oauth-http-status-code-reference?hl=ko

 

โœ… ์—๋Ÿฌ ํ•ด๊ฒฐ์— ๋„์›€์„ ์ค€ ํŽ˜์ด์ง€๋“ค

- https://blog.timekit.io/google-oauth-invalid-grant-nightmare-and-how-to-fix-it-9f4efaf1da35

- https://groups.google.com/g/adwords-api/c/jBeyFbcim60?pli=1

 

728x90