디스코드로 로그인하는 기능을 추가할 필요성이 있었기에 추가했다.
처음엔 클라이언트에서의 로그인만 되길 원했으나 아쉽게도
discord 개발자 문서에 자바스크립트는 node.js만 지원했다.
우선 nodejs로 로그인 하는 방법이다.
디스코드 개발자 포탈로 들어가서 앱을 만들어야한다.
https://discord.com/developers/applications로 들어간다.
앱을 하나 만들고
해당 앱을 클릭하면 좌측 메뉴중 Settings > OAuth2 >General을 클릭한다.
클라이언트 아이디와 클라이언트 시크릿을 복사한다.
(클라이언트 시크릿은 발급 후 disable이 되므로 따로 저장하는 것을 추천)
****만약 Client Secret발급 중 인증하라는 팝업이 떴을 경우****
디스코드의 2단계 인증 절차를 적용시켜야한다.
나 같은 경우엔 핸드폰 어플리케이션 중 AUTHY라는 어플을 이용하여 발급 받았다.
AUTHY를 이용한 Discord 2단계 인증 적용 방법
****
다음으론 그 아래 Redirects에 http://localhost:8000/auth/discord을 추가한다.
(본인 로컬 포트에 따라 다름)
마지막으로 URL Generator에 들어가 가져오고자 하는 정보를 선택한 다음
SELECT REDIRECT URL에 방금 입력했던 http://localhost:8000/auth/discord을 선택하면
GENERATED URL 하나를 발급받는다.
이것 또한 어딘가에 저장해두면 좋다.
이제 디스코드의 설정은 끝이났다.
프로젝트를 만들자.
프로젝트에는 기본적으로 axios와 express가 필요하다.
axios외 다른 것을 이용할 시엔 다른 것 이용.
이제 아래 코드를 넣으면 잘 실행된다.
const express = require("express");
const axios = require("axios");
require("dotenv").config();
const PORT = 8000;
const app = express();
app.get("/", (req, res) => {
res.send(`
<div style="margin: 300px auto;
max-width: 400px;
display: flex;
flex-direction: column;
align-items: center;
font-family: sans-serif;"
>
<h3>Welcome to Discord OAuth NodeJS App</h3>
<p>Click on the below button to get started!</p>
<a
href=
"방금 발급 받은 GENERATED URL"
style="outline: none;
padding: 10px;
border: none;
font-size: 20px;
margin-top: 20px;
border-radius: 8px;
background: #6D81CD;
cursor:pointer;
text-decoration: none;
color: white;"
>
Login with Discord</a>
</div>
`);
});
console.log(process.env.CLIENT_SECRET);
app.get("/auth/discord", async (req, res) => {
const code = req.query.code;
const params = new URLSearchParams();
let user;
params.append("client_id", process.env.CLIENT_ID);
params.append("client_secret", process.env.CLIENT_SECRET);
params.append("grant_type", "authorization_code");
params.append("code", code);
params.append("redirect_uri", "http://localhost:8000/auth/discord");
try {
const response = await axios.post(
"https://discord.com/api/oauth2/token",
params
);
const { access_token, token_type } = response.data;
const userDataResponse = await axios.get(
"https://discord.com/api/users/@me",
{
headers: {
authorization: `${token_type} ${access_token}`,
},
}
);
console.log("Data: ", userDataResponse.data);
user = {
username: userDataResponse.data.username,
email: userDataResponse.data.email,
};
return res.send(`
<div style="margin: 300px auto;
max-width: 400px;
display: flex;
flex-direction: column;
align-items: center;
font-family: sans-serif;"
>
<h3>Welcome ${user.username}</h3>
<span>Email: ${user.email}</span>
<p>Your Discord App is connected to NodeJS!</p>
<img src="${user.avatar}"/>
</div>
`);
} catch (error) {
console.log("Error", error);
return res.send("Some error occurred! ");
}
});
app.listen(PORT, () => {
console.log(`App started on port ${PORT}`);
});
하지만 내가 원하던 방식은 아니었다.
분명 간단한 방법이었지만 백엔드와의 통신은 매우 귀찮았다.
그래서 찾았다. 나 대신 통신할 대체재를
Supabase라는 것인데 이 supabase는 구글 firebase를 엔터프라이즈 레벨에서도 사용하능하게 만든 오픈소스 프로젝트이다.
Supabase와 Firebase의 차이점은 몇가지 있지만, 자세한 점은 아래 링크에서 확인.
https://blog.logrocket.com/firebase-vs-supabase-choosing-right-tool-project/
우선 본인 환경은 CRA이다.
Supabase를 사용하기 Firebase처럼 몇가지 설정해야 할 것들이 있다.
https://app.supabase.com/projects에 접속하여 프로젝트를 생성한다.
해당 프로젝트를 생성한 후 클릭,
Authentication > URL Configuration > Redirect URLs에 https://localhost:3000/success를 등록한다.
본인이 https가 아닌 http일 경우 http로 변경.
다음으로
같은 Authentication에서 들어가면 Supabase가 지원하는 로그인 서비스를 확인할 수 있다.
Discord를 클릭,
Client ID와 Client Scret을 입력하면 된다.
Client ID와 Client Scret은 Discord에서 발급 받은 것을 사용하면 된다.
Redirect URL은 따로 복사한 후
Discord의 OAuth2 > General > Redirects에 추가하면 된다.
이제 설정은 끝이났다.
프로젝트를 하나 생성한 이후,
npm install @supabase/auth-ud-react @supabase/supabase-js react-router-dom
을 설치.
LoginPage.js 와 Success.js를 생성한다.
App.js
import React from "react";
import { Route, Routes } from "react-router-dom";
import SuccessPage from "./pages/SuccessPage";
import LoginPage from "./pages/LoginPage";
const App = () => {
return (
<Routes>
<Route path="/success" element={<SuccessPage />} />
<Route path="/" element={<LoginPage />} />
</Routes>
);
};
export default App;
Login.js
import React from "react";
const LoginPage = () => {
return (
<h1>login</h1>
);
};
export default LoginPage;
다음에 supabase client를 만든다.
이때 두 개의 값이 필요한데, 하나는 프로젝트 URL이고 다른 하나는 API키이다.
둘은 아래 사진에서 확인할 수 있다.
그 다음은 쉽다.
이제 완성된 코드를 보자.
Login.js
import React from "react";
import { createClient } from "@supabase/supabase-js";
import { Auth, ThemeSupa } from "@supabase/auth-ui-react";
import { useNavigate } from "react-router-dom";
const supabase = createClient(
process.env.REACT_APP_SUPABASE_PROJECT_URL,
process.env.REACT_APP_SUPABASE_PROJECT_API_KEY
);
const LoginPage = () => {
const navigate = useNavigate();
supabase.auth.onAuthStateChange(async (event) => {
if (event !== "SIGNED_OUT") {
//forward success url
navigate("/success");
} else {
//forward localhost 3000
navigate("/");
}
});
return (
<div style={{ color: "red" }}>
login
<Auth
supabaseClient={supabase}
appearance={{ theme: ThemeSupa }}
theme="dark"
providers={["discord"]}
/>
</div>
);
};
export default LoginPage;
Success.js
import React, { useEffect, useState } from "react";
import { createClient } from "@supabase/supabase-js";
import { Auth, ThemeSupa } from "@supabase/auth-ui-react";
import { useNavigate } from "react-router-dom";
const supabase = createClient(
"https://yczuwmfnhwaxfifchaem.supabase.co",
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InljenV3bWZuaHdheGZpZmNoYWVtIiwicm9sZSI6ImFub24iLCJpYXQiOjE2NzMyODMxMjksImV4cCI6MTk4ODg1OTEyOX0.-9ybzuG96idM_Eu_DcKSxDHLpB276RUa7ZbniJ6wwhg"
);
const SuccessPage = () => {
const [user, setUser] = useState({});
const navigate = useNavigate();
useEffect(() => {
async function getUserData() {
await supabase.auth.getUser().then((value) => {
if (value.data?.user) {
console.log(value.data.user);
setUser(value.data.user);
}
});
}
getUserData();
}, []);
async function signOutUser() {
const { error } = await supabase.auth.signOut();
navigate("/login");
}
return (
<h1 style={{ color: "red" }}>
{Object.keys(user) !== 0 && (
<>
success!!
<button onClick={() => signOutUser()}>signOut</button>
</>
)}
</h1>
);
};
export default SuccessPage;
완성된 모습
https://localhost:3000
https://localhost:3000/success
해당 코드는 가공시켜 프로젝트에 적용시켰음.
'자바스크립트' 카테고리의 다른 글
자바스크립트) 객체의 복사 (0) | 2023.05.30 |
---|---|
React) 구글 로그인 - @react-oauth/google (0) | 2023.03.30 |
AWS S3 이미지 업로드 with React (0) | 2023.01.25 |
use-query)useInfiniteQuery를 사용해보자. (0) | 2022.12.29 |
use-query) queryClient.invalidateQueries가 동작하지 않을 때. (0) | 2022.12.28 |