반응형
깃허브 데스크탑으로 프로젝트 관리하기 강의 오픈!! (인프런 바로가기)
참고
- GitHub OAuth Project Settings
- Material UI로 깃허브 로그인 프로필 만들기
- 깃허브 OAuth 콜백 처리하기
- 인증 토큰 획득 서버 구현하기
- 인증 토큰으로 로그인 상태 관리하기
- 로그인 정보를 활용하여 Commit Message 남기기
- 새 창으로 로그인해서 현재 상태 유지하기
로그인이 되지 않은 상태에서 편집을 하다가,
로그인 버튼을 누르면 callback으로 인해 편집된 내용이 사라지게 된다.
현재 상태를 유지한 채로 로그인을 하려면 window.open을 이용해 새 창을 열면 된다.
const handleSave = async () => {
let status = await gh.getLoginStatus();
if (status) {
let loginID = localStorage.getItem("LOGIN_ID");
let markDownContent = editorRef.current.getInstance().getMarkdown();
fileWrite(markDownContent, `submitted by ${loginID}`);
} else {
Swal.fire({
icon: "error",
title: "Oops...",
text: "로그인 해주세요!!",
showCancelButton: true,
}).then((result) => {
if (result.isConfirmed) {
const clientID = process.env.REACT_APP_CLIENT_ID;
const callbackURL = "http://localhost:3000/callback";
const loginURL = `https://github.com/login/oauth/authorize?client_id=${clientID}&scope=repo:status read:repo_hook user:email&redirect_uri=${callbackURL}`;
window.open(loginURL);
}
});
}
};
이제 새 창에서 로그인을 하였다.
따라서 편집기의 저장 버튼이 정상적으로 동작하게 된다.
전체 코드는 다음과 같다.
App.js
import React, { useEffect, useState } from "react";
import { Route, Link, Routes } from "react-router-dom";
import Home from "./page/Home";
import SimpleToastEditor from "./page/SimpleToastEditor";
import "./App.css";
import GitHubLoginButton from "./page/GitHubLoginButton";
import GitHubLoginCallback from "./page/GitHubLoginCallback";
import * as gh from "./githublibrary.js";
const App = () => {
const [loginStatus, setLoginStatus] = useState(false);
useEffect(() => {
gh.loginCheck(setLoginStatus);
}, []);
return (
<div>
<div className="router">
<GitHubLoginButton
loginStatus={loginStatus}
setLoginStatus={setLoginStatus}
/>
<span>
<Link to="/">Home</Link>
</span>
<span>
<Link to="/editor">Toast UI Editor</Link>
</span>
</div>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/editor" element={<SimpleToastEditor />} />
<Route
path="/callback"
element={
<GitHubLoginCallback
loginStatus={loginStatus}
setLoginStatus={setLoginStatus}
/>
}
/>
</Routes>
</div>
);
};
export default App;
GitHubLoginButton.js
import React from "react";
import Button from "@mui/material/Button";
import Box from "@mui/material/Box";
import Stack from "@mui/material/Stack";
import Avatar from "@mui/material/Avatar";
const clientID = process.env.REACT_APP_CLIENT_ID;
const callbackURL = "http://localhost:3000/callback";
const loginURL = `https://github.com/login/oauth/authorize?client_id=${clientID}&scope=repo:status read:repo_hook user:email&redirect_uri=${callbackURL}`;
const GitHubLoginButton = ({ loginStatus, setLoginStatus }) => {
const logout = () => {
setLoginStatus(false);
localStorage.removeItem("GITHUB_TOKEN");
localStorage.removeItem("AVATAR_URL");
localStorage.removeItem("LOGIN_ID");
};
return (
<div>
<Box sx={{ m: 2 }}>
{loginStatus === false && (
<div>
<Stack direction="row" spacing={2}>
<Avatar alt="GitHub Login" src="/static/images/avatar/1.jpg" />
<Button variant="outlined" color="secondary" href={loginURL}>
로그인
</Button>
</Stack>
</div>
)}
{loginStatus === true && (
<div>
<Stack direction="row" spacing={2}>
<Avatar
alt="GitHub Login"
src={localStorage.getItem("AVATAR_URL")}
/>
<Button variant="outlined" color="error" onClick={logout}>
로그아웃
</Button>
</Stack>
</div>
)}
</Box>
</div>
);
};
export default GitHubLoginButton;
GitHubLoginCallback.js
import React, { useEffect } from "react";
import { useNavigate } from "react-router-dom";
import axios from "axios";
import queryString from "query-string";
const clientID = process.env.REACT_APP_CLIENT_ID;
const GitHubLoginCallback = ({ loginStatus, setLoginStatus }) => {
const navigate = useNavigate();
const getAccessToken = async (code) => {
try {
let server = `http://192.168.55.120:3002`;
let accessInfo = await axios.get(
`${server}/githubLogin?code=${code}&clientID=${clientID}`
);
let token = accessInfo.data.token;
const userResponse = await axios.get("https://api.github.com/user", {
headers: {
Authorization: `Bearer ${token}`,
},
});
const userData = userResponse.data;
const avatarUrl = userData.avatar_url;
const loginID = userData.login;
console.log(userData);
console.log(avatarUrl);
console.log(loginID);
localStorage.setItem("GITHUB_TOKEN", token);
localStorage.setItem("AVATAR_URL", avatarUrl);
localStorage.setItem("LOGIN_ID", loginID);
setLoginStatus(true);
navigate('/', { replace: true });
} catch (e) {
console.log(e);
setLoginStatus(false);
}
};
const getCode = () => {
let qs = queryString.parse(window.location.search);
let code = qs.code;
getAccessToken(code);
};
useEffect(() => getCode(), []);
return <div>{loginStatus ? "로그인 성공!" : "로그인 실패..."}</div>;
};
export default GitHubLoginCallback;
githublibrary.js
import axios from "axios";
export const loginCheck = async (setLoginStatus) => {
let token = localStorage.getItem("GITHUB_TOKEN");
try {
const response = await axios.get("https://api.github.com/user", {
headers: {
Authorization: `Bearer ${token}`,
},
});
console.log(response);
setLoginStatus(true);
} catch (error) {
console.error("Error fetching user data:", error);
setLoginStatus(false);
}
};
export const getLoginStatus = async () => {
let token = localStorage.getItem("GITHUB_TOKEN");
try {
const response = await axios.get("https://api.github.com/user", {
headers: {
Authorization: `Bearer ${token}`,
},
});
console.log(response);
return true;
} catch (error) {
console.error("Error fetching user data:", error);
return false;
}
};
반응형
'개발 > React' 카테고리의 다른 글
리액트 - 파일 편집 후 메일 알림이 가도록 수정하기 with GitHub RESTful API (0) | 2023.09.02 |
---|---|
리액트 - 로컬 스토리지 유효기간 설정하기 (Setting Local Storage Expiration Time) (0) | 2023.08.21 |
리액트 - GitHub OAuth 로그인 정보를 활용하여 Commit Message 남기기 (0) | 2023.08.19 |
리액트 - GitHub OAuth 인증 토큰으로 로그인 상태 관리하기 (GitHub OAuth Login Status) (0) | 2023.08.19 |
리액트, Node JS - 인증 토큰 획득 서버 구현하기 (GitHub Access Token Server with Node JS) (0) | 2023.08.19 |
댓글