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

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

[์›น ๊ฐœ๋ฐœ ํ”„๋กœ์ ํŠธ] 9. ์Šคํ”„๋ง Spring ๊ตฌ๊ธ€ ์†Œ์…œ ๋กœ๊ทธ์ธ ๋กœ์ง ๋ณ€๊ฒฝ (๋ฆฌ์•กํŠธ ๋„ค์ดํ‹ฐ๋ธŒ ์›น๋ทฐ ๊ด€๋ จ) ๋ณธ๋ฌธ

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

[์›น ๊ฐœ๋ฐœ ํ”„๋กœ์ ํŠธ] 9. ์Šคํ”„๋ง Spring ๊ตฌ๊ธ€ ์†Œ์…œ ๋กœ๊ทธ์ธ ๋กœ์ง ๋ณ€๊ฒฝ (๋ฆฌ์•กํŠธ ๋„ค์ดํ‹ฐ๋ธŒ ์›น๋ทฐ ๊ด€๋ จ)

adorableco 2024. 2. 2. 00:19
๋ฐ˜์‘ํ˜•

์ด๋ฒˆ ํ”„๋กœ์ ํŠธ ์ค‘์— ์ ค ๋ง‰ํ˜”๋˜ ๋ฌธ์ œ...
๋ฌธ์ œ๊ฐ€ ์–ด๋””์„œ ๋ฐœ์ƒํ–ˆ๋ƒ.. ํ•˜๋ฉด์€

์›๋ž˜ ๊ตฌ๊ธ€ ์†Œ์…œ๋กœ๊ทธ์ธ์˜ A to Z๋ฅผ ๋ฐฑ์—”๋“œ์—์„œ ๋‹ด๋‹นํ•˜๋„๋ก ๊ตฌํ˜„์„ ํ–ˆ๋‹ค.

์˜ค๋žœ๋งŒ์— ์‹œํ€€์Šค ๋‹ค์ด์–ด๊ทธ๋žจ๋„ ๊ทธ๋ ค๋ดค๋Š”๋ฐ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

(draw. io ๋Š” ๊ทธ๋ฆฌ๊ธฐ๋Š” ์ฐธ ํŽธ๋ฆฌํ•œ๋ฐ ์ €์žฅํ•  ๋•Œ ํ™”์งˆ์ด ์กฐ๊ธˆ๋งŒ ๋” ๊ฐœ์„ ๋˜๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค.. .ใ…Ž..)

 

 

 

๋กœ๊ทธ์ธ ์š”์ฒญ๋ถ€ํ„ฐ Authorization Code๋ฅผ ๋ฐ›์•„ ์‚ฌ์šฉ์ž ์ •๋ณด ์š”์ฒญํ•˜๋Š” ๊ฒƒ๊นŒ์ง€ ์„œ๋ฒ„์—์„œ ์ง„ํ–‰์„ ํ•˜๊ณ 

์ตœ์ข… accessToken ๋˜๋Š” ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ํด๋ผ์ด์–ธํŠธ ์ธก์œผ๋กœ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ๊ตฌํ˜„ํ–ˆ์—ˆ๋‹ค.
(ํšŒ์›์ด๋ฉด ์ธ์ฆ/์ธ๊ฐ€๋ฅผ ์œ„ํ•œ accessToken๋งŒ, ๋น„ํšŒ์›์ด๋ผ๋ฉด ํšŒ์›๊ฐ€์ž…์„ ๋ฐ”๋กœ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก

์‚ฌ์šฉ์ž์ •๋ณด (name, email, picture) ์„ ๋‹ด์•„๋ณด๋‚ธ๋‹ค.

๊ทผ๋ฐ ์ •๋ง ์˜ˆ์ƒ์น˜๋„ ๋ชปํ•˜๊ฒŒ ํ”„๋ก ํŠธ(React Native Expo) ์™€์˜ ์—ฐ๊ฒฐ์—์„œ ์˜ค๋ฅ˜๊ฐ€ ๋‚ฌ๋‹ค..

์›น์ด๋ž‘ ์•ฑ์ด๋ž‘ ๋ฌด์ž‘์ • ๊ฐ™์ง„ ์•Š๊ฒ ์ง€.. ๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๊ธด ํ•˜์ง€๋งŒ...

 

์ฒ˜์Œ ์‹œ๋„๋Š” WebView ๋ฅผ ํ†ตํ•ด ๊ตฌ๊ธ€ ๋กœ๊ทธ์ธ ์ฐฝ์œผ๋กœ ์ด๋™ํ•˜๋Š” ๊ฒƒ์ด์—ˆ๋‹ค. ์ผ๋‹จ ์—ฌ๊ธฐ์„œ๋„ ๋งค๋„๋Ÿฝ์ง€๋งŒ์€ ์•Š์•˜๋˜๊ฒŒ, ๊ตฌ๊ธ€์ด ์›น๋ทฐ ์ด์šฉ์„ ๋ง‰์•„์„œ ์›น๋ทฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด userAgent ์— ๋‹ค๋ฅธ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์ž…๋ ฅํ•˜์—ฌ ์šฐํšŒํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•ด์•ผ ํ–ˆ๋‹ค.

<WebView
                source={{ uri: url }}
                onNavigationStateChange={handleNavigationStateChange}
                userAgent='Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36'
                style={{ flex: 1 }}
            />

 

๊ทธ๋ฆฌ๊ณ  ๋ฉ”์ธ ๋ฌธ์ œ๋Š” ๋กœ๊ทธ์ธ ์™„๋ฃŒ ํ›„์— ๊ฐ€์ ธ์™€์•ผํ•  json ์ •๋ณด๋“ค์„ ์ด ์›น๋ทฐ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์•ฑ์œผ๋กœ ๋ณด๋‚ผ ๋ฐฉ๋ฒ•์„ ๋„์ €ํžˆ ๋ชป์ฐพ๊ฒ ๋‹ค๋Š” ๊ฒƒ์ด์—ˆ๋‹ค. (์•„๋งˆ ์• ์ดˆ์— ๋ฐฉ๋ฒ•์ด ์—†๋Š” ๊ฒƒ ๊ฐ™๋‹ค... ์žˆ์œผ๋ฉด ์•Œ๋ ค์ฃผ์‹œ๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค..)

 

 

 


๋กœ๊ทธ์ธ์„ ํ•˜๊ณ 


์‚ฌ์šฉ์ž ์ •๋ณด json ์ด ๋ฐ˜ํ™˜๋œ ์ƒํƒœ์ด๋‹ค.

ํ˜„์žฌ ์•ฑ์ด ์•„๋‹ˆ๋ผ ์™ธ๋ถ€ ๋ธŒ๋ผ์šฐ์ €์— ์žˆ๋Š” ์ƒํƒœ์ด๋‹ˆ ๊ฐ€์ ธ์˜ฌ ์ˆ˜๊ฐ€ ์—†๋Š” ๊ฒƒ์ด๋‹ค.๋ฌด์ž‘์ • ์—ฌ๊ธฐ์„œ ์–ด๋–ป๊ฒŒ ๊ฐ€์ ธ์˜ฌ๊นŒ๋งŒ ํ•˜๋ฃจ์ข…์ผ ๊ณ ๋ฏผํ•˜๋‹ค๊ฐ€

๋‹ค๋ฅธ ๋™๊ธฐ์—๊ฒŒ ์˜๊ฒฌ์„ ๊ตฌํ•ด๋ณธ ๊ฒฐ๊ณผ ๊ตฌ๊ธ€ ๋กœ๊ทธ์ธ ์š”์ฒญ์„ ํ”„๋ก ํŠธ์—์„œ ๊ตฌ๊ธ€๋กœ ์ง์ ‘ ๋ณด๋‚ด๋Š” ๊ฒƒ์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค!

๋ณดํ†ต์€ ์ด๋Ÿฐ ๋กœ์ง์œผ๋กœ ํ•œ๋‹ค๋„ค์š”)

๊ทธ๋ž˜์„œ ์ตœ์ข…์ ์œผ๋กœ ๋ณ€๊ฒฝํ•œ ๊ฒƒ์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค

 

 

 

 

ํ™•์‹คํžˆ ๋ญ”๊ฐ€ ๋” ๋ถ„์—…ํ™”๊ฐ€ ๋˜์—ˆ๋‹ค

๋ฐฑ์—”๋“œ ์ฝ”๋“œ๋Š” ํฌ๊ฒŒ ๋‹ฌ๋ผ์ง„๊ฑด ์—†์–ด์„œ ํ”„๋ก ํŠธ ์ชฝ ์ฝ”๋“œ๋งŒ ํ•œ๋ฒˆ์”ฉ ์–ธ๊ธ‰์„ ํ•˜๊ฒ ๋‹ค

/** @format */

import * as React from "react";
import * as WebBrowser from "expo-web-browser";
import * as Google from "expo-auth-session/providers/google";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { Button, View, Text, StyleSheet, TouchableOpacity } from "react-native";
import { useEffect } from "react";
import axios from "axios";

WebBrowser.maybeCompleteAuthSession();
export default function GoogleLogin() {
  const [request, response, promptAsync] = Google.useAuthRequest({
    webClientId: process.env.EXPO_PUBLIC_WEB_CLIENT_ID,
    androidClientId: EXPO_PUBLIC_ANDROID_CLIENT_ID,
  });

  const [userInfo, setUserInfo] = React.useState(null);

  const handleSignInWithGoogle = async () => {
    const user = await AsyncStorage.getItem("@accessToken");
    if (!user) {
      if (response?.type === "success") {
        await sendToken(response.authentication?.accessToken);
      }
    }
  };

  //๊ตฌ๊ธ€๋กœ๊ทธ์ธ์„ ํ•ด์„œ ๋ฐ›์€ ํ† ํฐ์„ ๋ฐฑ์—”๋“œ๋กœ ๋ณด๋‚ด์„œ ๋””๋น„์— ์žˆ๋Š” ํšŒ์› ๋‚ด์šฉ ์กฐํšŒ ์˜ˆ์ •
  const sendToken = async (token) => {
    await axios
      .get(`http://fit-friends.duckdns.org:8081/api/login/${token}`)
      .then(async (res) => {
        if (res.data.accessToken == null) {
          setUserInfo(res.data);
          // ํšŒ์›๊ฐ€์ž… ํ•ด์•ผ ํ•จ
        } else {
          console.log("accessToken = ", res.data.accessToken);
          await AsyncStorage.setItem(
            "@accessToken",
            JSON.stringify(res.data.accessToken),
          );
        }
      });
  };

  const handleLogout = async () => {
    await AsyncStorage.removeItem("@user");
    setUserInfo(null);
  };

  useEffect(() => {
    handleSignInWithGoogle();
  }, [response]);

  return (
    <View>
      <TouchableOpacity
        style={[styles.buttonStyle, { marginBottom: 18 }]}
        disabled={!request}
        title='Login'
        onPress={() => {
          promptAsync();
        }}
      >
        <Text style={styles.buttonTextStyle}>๋กœ๊ทธ์ธํ•˜์—ฌ ์‹œ์ž‘ํ•˜๊ธฐ</Text>
      </TouchableOpacity>

      <Button title='logout' onPress={() => handleLogout()} />
    </View>
  );
}

 

๊ตฌ๊ธ€ ๋กœ๊ทธ์ธ์„ ์ง€์›ํ•˜๋Š” expo ์˜ ์—ฌ๋Ÿฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ตฌํ˜„ํ•˜์˜€๋‹ค.

 

 

๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด

const handleSignInWithGoogle = async () => {
    const user = await AsyncStorage.getItem("@accessToken");
    if (!user) {
      if (response?.type === "success") {
        await sendToken(response.authentication?.accessToken);
      }
    }
  };

 

์ด ๋ฉ”์„œ๋“œ์—์„œ ๋จผ์ € AsyncStorage ์— ์ €์žฅ๋ผ์žˆ๋Š” accessToken ๊ฐ’์„ ๊ฐ€์ ธ์™€ ๋กœ๊ทธ์ธ ์ƒํƒœ์ธ์ง€ ํ™•์ธํ•˜๊ณ  ๊ฐ’์ด ์—†๋‹ค๋ฉด

๋ฐฑ์—”๋“œ์—์„œ ๊ตฌ๊ธ€์—๊ฒŒ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ์š”์ฒญํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌ๊ธ€๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ ์ฝ”๋“œ(๋ณ€์ˆ˜ accessToken) ๋ฅผ ์ „๋‹ฌํ•œ๋‹ค.

๊ทธ๊ฒƒ์ด ์•„๋ž˜์˜ sendToken ๋ฉ”์„œ๋“œ์ด๋‹ค.

 

๋‹ค์‹œ๋ณด๋‹ˆ ํ—ท๊ฐˆ๋ฆฌ๊ฒŒ ์ ์–ด๋’€๋Š”๋ฐ AsyncStorage์— ์ €์žฅํ•ด๋‘๋Š” accessToken ์€ ์Šคํ”„๋ง ์„œ๋ฒ„์—์„œ ์ œ๊ณตํ•˜๋Š” ์‚ฌ์šฉ์ž ์ธ๊ฐ€์šฉjwt ํ† ํฐ์ด๊ณ  ๋ฐฑ์—”๋“œ์— ๋ณด๋‚ด๋Š” accessToken ์€ ๊ตฌ๊ธ€์šฉ ์ธ๊ฐ€์ฝ”๋“œ์ด๋‹ค!

sendToken()

    await axios
      .get(`{๋ฐฑ์—”๋“œ api ์ฃผ์†Œ}/api/login/${token}`)
      .then(async (res) => {
        if (res.data.accessToken == null) {
          setUserInfo(res.data);
          // ํšŒ์›๊ฐ€์ž… ํ•ด์•ผ ํ•จ
        } else {
          console.log("accessToken = ", res.data.accessToken);
          await AsyncStorage.setItem(
            "@accessToken",
            JSON.stringify(res.data.accessToken),
          );
        }
      });
  };

 

 

AsyncStorage ๋Š” @react-native-async-storage/async-storage ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์žˆ๋Š”๊ฑด๋ฐ
์•ฑ์—์„œ ์ž‘๋™ ์‹œ์— ์›น ๋ธŒ๋ผ์šฐ์ €์— ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€ ์—ญํ• ์„ ํ•˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค.
์‹ค์ œ๋กœ ์ง€๊ธˆ expo ์•ฑ์ด ์•ˆ๋“œ๋กœ์ด๋“œ์—์„œ ์˜ค๋ฅ˜๊ฐ€ ๊ณ„์† ๋‚˜์„œ ์›น์œผ๋กœ ๊ฐœ๋ฐœ์„ ํ•˜๊ณ  ์žˆ๋Š”๋ฐ
ํ™•์ธํ•ด๋ณด๋ฉด ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— accessToken ๊ฐ’์ด ์ €์žฅ๋œ๋‹ค.



๋“œ๋””์–ด ๋‚ด๊ฐ€ ์ƒ๊ฐํ–ˆ๋˜๋Œ€๋กœ ์ž‘๋™์„ ํ•œ๋‹ค..... ์•„์ง ํ•ด๊ฒฐํ•  ๋ฌธ์ œ๋“ค์€ ์žˆ๊ธด ํ•˜์ง€๋งŒ (expo ์•ฑ์ด ์•ˆ๋“œ๋กœ์ด๋“œ ๋นŒ๋“œ๊ฐ€ ์•ˆ๋จ, expo๋Š” .env ์˜ ๋ณ€์ˆ˜ ์ด๋ฆ„์„ EXPO_PUBLIC_{NAME} ์œผ๋กœ ํ•˜๋ฉด ๋œ๋‹ค๋Š”๋ฐ ๋ณ€์ˆ˜๊ฐ’์ด ๋ถˆ๋Ÿฌ์™€์ง€์งˆ ์•Š์Œ..)

๊ทธ๋ž˜๋„ ๊ฐ€์žฅ ํฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด์„œ ๋‹คํ–‰์ด๋‹ค....

ํ–…์‚ํ–…์‚.........

๋ฐ˜์‘ํ˜•