본문 바로가기
개발/React

리액트 - 로그인한 사용자만 댓글 기능 사용하기 with react-comments-section (GitHub OAuth Login)

by 피로물든딸기 2023. 11. 15.
반응형

리액트 전체 링크

Git / GitHub 전체 링크

 

참고

- https://www.npmjs.com/package/react-comments-section

- https://riyanegi.github.io/react-comments-documentation/

 

- Toast UI Editor with OAuth to Access GitHub

- 깃허브 OAuth 콜백 처리하기

- GitHub OAuth 인증 토큰으로 로그인 상태 관리하기

 

댓글 기능 만들기 with react-comments-section
로그인한 사용자만 댓글 기능 사용하기
GitHub RESTful API로 댓글 저장하기
리액트 쿠키로 GitHub OAuth 로그인 인증 관리하기

- Mui Pagination으로 댓글 페이지로 나누기

 

react-comments-section의 Component에서 currentUser를 null로 설정해보자.

  let currentUser = null;
  // let currentUser = {
  //   currentUserId: "01a",
  //   currentUserImg:
  //     "https://ui-avatars.com/api/name=Riya&background=random",
  //   currentUserProfile:
  //     "https://www.linkedin.com/in/riya-negi-8879631a9/",
  //   currentUserFullName: "Riya Negi",
  // };
  
  ...
  
    <CommentSection
    currentUser={currentUser}
    logIn={{
      loginLink: "http://localhost:3001/",
      signupLink: "http://localhost:3001/",
    }}
    ...
  />

 

사용자 정보가 없는 경우 Log In Sign Up 버튼이 나타나게 되고, 클릭하면 login에 설정한 링크로 이동하게 된다.

 

로그인 버튼을 클릭하면 로그인이 되어 댓글을 남길 수 있도록 해보자.


깃허브 로그인 기능 연동

 

- Toast UI Editor with OAuth to Access GitHub

- 깃허브 OAuth 콜백 처리하기

- GitHub OAuth 인증 토큰으로 로그인 상태 관리하기

 

위의 세 링크를 참고하여 코드를 추가해보자.

 

먼저 App.js에서 로그인 체크 함수를 실행하기 위해 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);
  }
};

 

App.js는 다음과 같다.

login 상태를 관리하는 변수현재 유저의 정보를 가지는 변수를 useState로 관리한다.

loginStatustrue라면 LOGIN_ID와 AVATAR_URL, 그리고 profile URL을 설정한다.

그리고 currentUser를 ReactComments의 props로 넘겨준다.

import React, { useEffect, useState } from "react";
import { Route, Link, Routes } from "react-router-dom";

import "./App.css";

// ...
import ReactComments from "./page/ReactComments";
import GitHubLoginCallBack from "./page/GitHubLoginCallback";

import * as gh from "./githublibrary.js";

const App = () => {
  const [loginStatus, setLoginStatus] = useState(false);
  const [currentUser, setCurrentUser] = useState(null);

  useEffect(() => {
    if(loginStatus === false) return;
    let loginID = localStorage.getItem("LOGIN_ID");
    let url = localStorage.getItem("AVATAR_URL");
    let profile = `https://github.com/${loginID}`;

    setCurrentUser({
      currentUserId: loginID,
      currentUserImg: url,
      currentUserProfile: profile,
      currentUserFullName: loginID,
    });
  }, [loginStatus]);

  useEffect(() => {
    gh.loginCheck(setLoginStatus);
  }, []);

  return (
    <div className="App">
      <div className="router">
        {...}
        <span>
          <Link to="/comments">Comments</Link>
        </span>
      </div>
      <div>
        <Routes>
          {...}
          <Route
            path="/comments"
            element={<ReactComments currentUser={currentUser} />}
          />
          <Route
            path="/callback"
            element={
              <GitHubLoginCallBack
                loginStatus={loginStatus}
                setLoginStatus={setLoginStatus}
              />
            }
          />
        </Routes>
      </div>
    </div>
  );
};

export default App;

 

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;

 

ReactComments는 깃허브 로그인을 위해 loginURL을 설정한다.

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}`;

 

위의 login 버튼을 누르면 loginURL로 이동하여 깃허브 로그인을 할 수 있게 된다.

그리고 signupLink깃허브 링크를 설정하였다.

      <CommentSection
        currentUser={getCurrentUser}
        logIn={{
          loginLink: loginURL,
          signupLink: "https://github.com/",
        }}

 

currentUser는 다음과 같이 얻는다.

/comments 라우터로 바로 이동할 경우, login 정보를 얻을 수 없기 때문에 추가한 방어코드다.

  const getCurrentUser = () => {
    if (currentUser === null) {
      let loginID = localStorage.getItem("LOGIN_ID");
      let url = localStorage.getItem("AVATAR_URL");
      let profile = `https://github.com/${loginID}`;

      if(loginID === null) return null;

      return {
        currentUserId: loginID,
        currentUserImg: url,
        currentUserProfile: profile,
        currentUserFullName: loginID,
      }
    }

    return currentUser;
  };

 

ReactComments.js의 전체 코드는 다음과 같다.

import React from "react";
import { CommentSection } from "react-comments-section";
//import 'react-comments-section/dist/index.css';
import "../css/comment.css";

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 ReactComments = ({ currentUser }) => {
  const data = [
    {
      userId: "02b",
      comId: "017",
      fullName: "Lily",
      userProfile: "https://www.linkedin.com/in/riya-negi-8879631a9/",
      text: "I think you have a point🤔",
      avatarUrl: "https://ui-avatars.com/api/name=Lily&background=random",
      replies: [],
    },
  ];

  const onSubmitAction = (data) => {
    console.log("check submit, ", data);
  };

  // const onDeleteAction
  // const onReplyAction
  // const onEditAction

  const currentData = (data) => {
    console.log("current data", data);
  };

  const getCurrentUser = () => {
    if (currentUser === null) {
      let loginID = localStorage.getItem("LOGIN_ID");
      let url = localStorage.getItem("AVATAR_URL");
      let profile = `https://github.com/${loginID}`;

      if(loginID === null) return null;

      return {
        currentUserId: loginID,
        currentUserImg: url,
        currentUserProfile: profile,
        currentUserFullName: loginID,
      }
    }

    return currentUser;
  };

  return (
    <div>
      <CommentSection
        currentUser={getCurrentUser}
        logIn={{
          loginLink: loginURL,
          signupLink: "https://github.com/",
        }}
        commentData={data}
        currentData={currentData}
        onSubmitAction={onSubmitAction}
        hrStyle={{ border: "0.5px solid #ff0072" }}
        inputStyle={{ border: "1px solid rgb(208 208 208)" }}
        formStyle={{ backgroundColor: "white" }}
        submitBtnStyle={{
          border: "1px solid black",
          backgroundColor: "black",
          padding: "7px 15px",
        }}
        cancelBtnStyle={{
          border: "1px solid gray",
          backgroundColor: "gray",
          color: "white",
          padding: "7px 15px",
        }}
        replyInputStyle={{ borderBottom: "1px solid black", color: "black" }}
        advancedInput={true}
        removeEmoji={false}
      />
    </div>
  );
};

export default ReactComments;

 

로컬에서 로그인이 정상적으로 이루어지는지 테스트해보자.

반응형

댓글