[토이] 개발 - 로그인&회원가입&로그아웃

최정윤·2023년 8월 29일
0

에반

목록 보기
8/12

📍 로그인 & 회원가입 페이지 템플릿 가져와서 구현하기

styled-component 간단 정리

https://kimdabin.tistory.com/entry/Styled-Components-%EA%B0%84%EB%8B%A8-%EC%A0%95%EB%A6%AC-Basic

styled-component 호버기능 넣기

https://wnsdufdl.tistory.com/109#:~:text=hover%EB%8A%94%20element%EC%97%90%20%EB%A7%88%EC%9A%B0%EC%8A%A4,%EC%88%98%20%EC%9E%88%EA%B2%8C%20%ED%95%98%EB%8A%94%20%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC%EC%9D%B4%EB%8B%A4.

로그인 / 회원가입 페이지 디자인 스타일 모음

https://inpa.tistory.com/entry/CSS-%F0%9F%92%8D-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%ED%9A%8C%EC%9B%90%EA%B0%80%EC%9E%85-%ED%8E%98%EC%9D%B4%EC%A7%80-%EC%8A%A4%ED%83%80%EC%9D%BC-%F0%9F%96%8C%EF%B8%8F-%EB%AA%A8%EC%9D%8C

▶️ login.js

              <Link to={"/calendar"} style={{ textDecoration: 'none' }}>
                <button>Sign up</button>
              </Link>

https://velog.io/@rmaomina/compatibility-rrd5pre-react18
-> 버전 변경해줬더니 더 난리났다..

npm cache clean --force
npm install

캐시 삭제 및 의존성 재설치 이후 다시 원상복구;;;

-> 잘못된 태그에 link를 걸어서 난 오류였다. 난 바보..

📍 카카오 소셜 로그인 구현

[참고링크]

[카카오 developer]

axios 설치

npm install axios --force

📍 rest api 통신하기

test code 백업

  // ================================ rest api로 통신하기 ==================================== 

  const [data, setData] = useState(null);
  const [token, setToken] = useState(null);
  
  useEffect(() => {
    const checkEmail = async () => {
      const payload = { 
        userEmail: "use3311@email.com",
        userPassword: "user1password"
       };
      
      try {
        const response = await axios.post('http://13.209.16.226:8080/api/auth/signIn', payload);
        console.log(response.data); 
        setData(response.data); // 응답 데이터를 state 변수에 저장
        setToken(response.data.data.token); // Save the token to state
      } catch (error) {
        console.error(error);
      }
    };
    checkEmail();

  }, []); // 빈 배열을 dependency로 전달하여 마운트 시 한 번만 실행되도록 함
  console.log(data);

  useEffect(() => {
    if (!token) return; // If there's no token yet, don't do anything

    const fetchData = async () => {
      try{
        const response = await axios.get('http://13.209.16.226:8080/api/diary/view?addDate=2023-01-01', {
          headers: { Authorization: `Bearer ${token}` } // Use the token here
        });
        
        console.log(response.data);
      } catch (error) {
         console.error("Error fetching data: ", error);
       }
     };
     
     fetchData();
   }, [token]); // Run this effect whenever the token changes


  // ================================ 메세지 전송 코드 ==================================== 
  //  useEffect(() => {
  //   if (!token) return; // If there's no token yet, don't do anything
  //   const sendData = async () => {
  //     try{
  //       const payload = { 
  //         diaryDetail: "메세지 전송 성공~!",
  //         addDate: "2023-07-01"
  //        };

  //        // Replace 'http://your-api-url' with your actual API endpoint
  //        const response = await axios.post('http://13.209.16.226:8080/api/diary/create', payload ,{
  //          headers: { Authorization: `Bearer ${token}` } // Use the token here
  //        });
        
  //        console.log(response.data);
  //      } catch (error) {
  //         console.error("Error sending data: ", error);
  //      }
  //    };
     
  //    sendData();
  //  }, [token]); // Run this effect whenever the token changes

📍 회원가입 db 연결

새 주소 : http://3.36.100.202:8080

📍 쿠키로 token 유지하기

https://www.youtube.com/watch?v=VePjN663uwc

npm install js-cookie --force
npm install react-cookie --force

📍 JWT 토큰 생성

https://www.youtube.com/watch?v=iSUH5TvIaFM

react로 jwt 로그인 구현하기

https://www.youtube.com/watch?v=KMJE9FIDZl8
https://careerly.co.kr/qnas/4458

react login 결과 recoil을 이용해서 전역으로 관리

https://www.youtube.com/watch?v=joMOF30x_NY

npm install recoil --force

-> 서버와 통신하여 받아온 정보를 전역변수에 넣어 어떤 페이지에서도 해당 변수에 저장된 정보를 사용할 수 있게끔 하는것이다.

recoil persist로 새로고침 해도 로그인 유지되게 하기

https://youtu.be/yAodvlX7oug?si=hTU0ulx4-vink6d-

npm install recoil-persist --force

-> 사용자가 직접 캐시를 지워주기 전까지 받아온 정보를 계속 유지시켜주는 것이다.

위 방법들로 시행하려 했으나 서연이가 보내준 서버 데이터상에는
exprTime: 3600000
으로 설정되어 있어서 이미 만료 시간에 대해 명시해서 get 받아지는 상황이였다.
따라서 위의 방법은 적절하지 않다고 판단하여 서연이가 보내준 영상으로 다시 로그인/회원가입/로그인유지/로그아웃 기능을 구현하기로 했다.

📍 스프링과 연결하여 로그인하기

강의 영상 따라하기 전에 이전 나의 코드 backup 해놓기 (230914)

login.js

import {Link} from 'react-router-dom';
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { useNavigate } from "react-router-dom";
import { useCookies } from 'react-cookie';
// import Cookies from 'js-cookie';
import '../component_css/login.css';
import {
    LoginWrapper,
    LoginTitle,
    LoginContent,
    IdInput,
    PasswordInput,
    LoginBtn,
    SocialContent,
    GoogleBtn,
    NaverBtn,
    KakaoeBtn,
} from '../component_css/login_style';

const Login = () => {
  // 카카오 소셜 로그인
  const REST_API_KEY = '3eb202eb62b260eb7db3b39958379429';
  const REDIRECT_URI = 'http://localhost:3000/calendar';
  const link = `https://kauth.kakao.com/oauth/authorize?client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}&response_type=code`;

  const loginHandler = () => {
    window.location.href = link;
  };

// function Login() {
  const [isSignIn, setIsSignIn] = useState(true);

  // useEffect(() => {
  //   setTimeout(() => {
  //     setIsSignIn(true);
  //   }, 200);
  // }, []);

  const handleToggle = () => {
    setIsSignIn((prevState) => !prevState);
  };

  const handleSignUpClick = () => {
    console.log('Sign up button clicked'); // 클릭 시 콘솔에 메시지 출력
  };

// ================================= 회원가입 =================================

  const [name, setName] = useState("");
  const [nickname, setNickname] = useState("");
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [confirmPassword, setConfirmPassword] = useState("");
  const [phoneNum, setPhoneNum] = useState("");
  const [birthDate, setBirthDate] = useState(null);
  const [gender, setGender] = useState("");

  const signupSubmit = async (e)=>{
    e.preventDefault();
    // Check if any field is empty
    // if(name === "" || nickname === "" || email === "" || password === "" || confirmPassword === "" || phoneNum === "" || birthDate == null || gender === "") {
    //   alert("모든 필드를 채워주세요.");
    //   return;
    // }

    if(password!==confirmPassword){
        alert("비밀번호가 일치하지 않습니다.")
        return;
    }
    try{
        let res=await axios.post('http://3.36.100.202:8080/api/auth/signUp',{
            name,
            nickname,
            email,
            password,
            phoneNum,
            birthDate,
            gender
        })
        console.log(res.data);
        // Clear the input fields after successful submission
        setName("");
        setNickname("");
        setEmail("");
        setPassword("");
        setConfirmPassword("");
        setPhoneNum("");
        setBirthDate(null);
        setGender("");

        // Check if the request was successful
        if(res.status === 200) { 
          window.location.reload();
        }

    }catch(err){
        console.error(err);
    }
}

// ================================= 로그인 =================================
const [loginemail, setloginEmail] = useState("");
const [loginpassword, setloginPassword] = useState("");

let navigate = useNavigate();

// Initialize cookie hook
const [cookies, setCookie] = useCookies(['token']);

const signinSubmit=async (e)=>{
  e.preventDefault();
  try{
      let res=await axios.post('http://3.36.100.202:8080/api/auth/signIn',{
          userEmail: loginemail,
          userPassword: loginpassword
      })
      console.log(res.data);

      // Check if the request was successful
      if(res.status === 200) {
        // Save the token to a cookie
        setCookie('token', res.data.token);

        // Save the token to a cookie
        // Cookies.set('token', res.data.token);
        
        // Navigate to /calendar page
        navigate("/calendar");
}
  }catch(err){
      console.error(err);
  }
}

  return (
    <div className="login">
      <div className="login_wrapper">
        <div id="container" className={`container ${isSignIn ? 'sign-in' : 'sign-up'}`}>
          <div className="login_row">
            <div className="login_col align-items-center flex-col sign-up">
              <div className="form-wrapper align-items-center">
                <div className="form sign-up">
                <LoginTitle src={'img/logo.png'}></LoginTitle>
                <form onSubmit={signupSubmit}>
                  <div className="input-group">
                    <i className="bx bxs-user"></i>
                    <input type="text" placeholder="이름" onChange={e => setName(e.target.value)}/>
                  </div>
                  <div className="input-group">
                    <i className="bx bxs-user"></i>
                    <input type="text" placeholder="닉네임" onChange={e => setNickname(e.target.value)}/>
                  </div>
                  <div className="input-group">
                    <i className="bx bx-mail-send"></i>
                    <input type="email" placeholder="이메일" onChange={e => setEmail(e.target.value)} />
                  </div>
                  <div className="input-group">
                    <i className="bx bxs-lock-alt"></i>
                    <input type="password" placeholder="비밀번호" onChange={e=>setPassword(e.target.value)}/>
                  </div>
                  <div className="input-group">
                    <i className="bx bxs-lock-alt"></i>
                    <input type="password" placeholder="비밀번호 확인" onChange={e=>setConfirmPassword(e.target.value)}/>
                  </div>
                  <div className="input-group">
                    <i className="bx bxs-lock-alt"></i>
                    <input type="tel" placeholder="전화번호" onchange ={ e=>setPhoneNum ( e.target.value )}/>
                  </div>
                  <div className="input-group">
                    <i className="bx bxs-lock-alt"></i>
                    <input type="date" placeholder="생일" onchange ={ e=>setBirthDate ( e.target.value )}/>
                  </div>
                  <div className="gender-group">
                    <i className="bx bxs-lock-alt"></i>
                    <div>
                      <label for="male">남성</label>
                      <input type="radio" name="gender" id="male" onchange ={()=>setGender('남성')}/>
                    </div>
                    <div>
                      <label for="female">여성</label>
                      <input type="radio" name="gender" id="female" onChange={()=>setGender('여성')}/>
                    </div>
                  </div>

                  <button onClick={handleSignUpClick}>Sign up</button>
                </form>
                  <p>
                    <span>Already have an account?</span>
                    <b onClick={handleToggle} className="pointer">
                      Sign in here
                    </b>
                  </p>
                </div>
              </div>
            </div>
            <div className="login_col align-items-center flex-col sign-in">
              <div className="form-wrapper align-items-center">
                <div className="form sign-in">
                <LoginTitle src={'img/logo.png'}></LoginTitle>
                <form onSubmit={signinSubmit}>
                  <div className="input-group">
                    <i className="bx bxs-user"></i>
                    <input type="email" placeholder="이메일" onChange={e => setloginEmail(e.target.value)}/>
                  </div>
                  <div className="input-group">
                    <i className="bx bxs-lock-alt"></i>
                    <input type="password" placeholder="비밀번호" onChange={e=>setloginPassword(e.target.value)}/>
                  </div>
                  {/* <Link to={"/calendar"} style={{ textDecoration: 'none' }}> */}
                    <button>Sign in</button>
                  {/* </Link> */}
                </form>
                  <SocialContent>
                        <GoogleBtn src={'img/google.png'}></GoogleBtn>
                        <NaverBtn src={'img/naver.png'}></NaverBtn>
                        <KakaoeBtn src={'img/kakao.png'} onClick={loginHandler}></KakaoeBtn>
                    </SocialContent>
                  <p>
                    <b>Forgot password?</b>
                  </p>
                  <p>
                    <span>Don't have an account?</span>
                    <b onClick={handleToggle} className="pointer">
                      Sign up here
                    </b>
                  </p>
                </div>
              </div>
              <div className="form-wrapper"></div>
            </div>
          </div>
          <div className="login_row content-row">
            <div className="login_col align-items-center flex-col">
              <div className="text sign-in">
                <h2>Welcome</h2>
              </div>
              <div className="img sign-in"></div>
            </div>
            <div className="login_col align-items-center flex-col">
              <div className="img sign-up"></div>
              <div className="text sign-up">
                <h2>Join with us</h2>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

export default Login;

수정된 코드

import {Link} from 'react-router-dom';
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { useNavigate } from "react-router-dom";
import { useCookies } from 'react-cookie';
import { useRecoilState } from 'recoil';
import {userState} from "./recoil";
import '../component_css/login.css';
import {
    LoginWrapper,
    LoginTitle,
    LoginContent,
    IdInput,
    PasswordInput,
    LoginBtn,
    SocialContent,
    GoogleBtn,
    NaverBtn,
    KakaoeBtn,
} from '../component_css/login_style';

const Login = () => {
  // 카카오 소셜 로그인
  const REST_API_KEY = '3eb202eb62b260eb7db3b39958379429';
  const REDIRECT_URI = 'http://localhost:3000/calendar';
  const link = `https://kauth.kakao.com/oauth/authorize?client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}&response_type=code`;

  const loginHandler = () => {
    window.location.href = link;
  };

// function Login() {
  const [isSignIn, setIsSignIn] = useState(true);

  // useEffect(() => {
  //   setTimeout(() => {
  //     setIsSignIn(true);
  //   }, 200);
  // }, []);

  const handleToggle = () => {
    setIsSignIn((prevState) => !prevState);
  };

  const handleSignUpClick = () => {
    console.log('Sign up button clicked'); // 클릭 시 콘솔에 메시지 출력
  };

// ================================= 회원가입 =================================

  const [name, setName] = useState("");
  const [nickname, setNickname] = useState("");
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [confirmPassword, setConfirmPassword] = useState("");
  const [phoneNum, setPhoneNum] = useState("");
  const [birthDate, setBirthDate] = useState(null);
  const [gender, setGender] = useState("");

  const signupSubmit = async (e)=>{
    e.preventDefault();
    // Check if any field is empty
    if(name.length === 0 || nickname.length === 0 || email.length === 0 || password.length === 0 || confirmPassword.length === 0 || phoneNum.length === 0 || birthDate == null || gender.length === 0) {
      alert("모든 필드를 채워주세요.");
      return;
    }

    if(password!==confirmPassword){
        alert("비밀번호가 일치하지 않습니다.")
        return;
    }
    try{
        let res=await axios.post('http://3.36.100.202:8080/api/auth/signUp',{
            name,
            nickname,
            email,
            password,
            phoneNum,
            birthDate,
            gender
        })
        console.log(res.data);
        // Clear the input fields after successful submission
        setName("");
        setNickname("");
        setEmail("");
        setPassword("");
        setConfirmPassword("");
        setPhoneNum("");
        setBirthDate(null);
        setGender("");

        // Check if the request was successful
        if(res.status === 200) { 
          window.location.reload();
        }

    }catch(err){
        console.error(err);
    }
}

// ================================= 로그인 =================================
const [loginemail, setloginEmail] = useState('');
const [loginpassword, setloginPassword] =  useState('');
const [user, setUser] = useRecoilState(userState);
const [cookies, setCookie] = useCookies();

let navigate = useNavigate();

const signinSubmit = async (e) => {
  // e.preventDefault();
  if (loginemail.length === 0 || loginpassword.length === 0){
    alert('이메일과 비밀번호를 입력하세요.');
    return;
  }
  try{
      let response = await axios
      .post('http://3.36.100.202:8080/api/auth/signIn',{
          userEmail: loginemail,
          userPassword: loginpassword
      })
      console.log(response.data)
      const responseData = response.data;
      if (!responseData.result) {
        console.log('로그인에 실패했습니다.')
        alert('로그인에 실패했습니다.');
        return;
      }
      else{
        console.log(response.data);
        const { token, exprTime } = responseData.data;
        const expires = new Date();
        expires.setMilliseconds(expires.getMilliseconds() + exprTime);

        setCookie('token', token, { expires });
        navigate("/calendar");
        // setUser(res.data.data.user);
      }
  }catch(err){
      console.error(err);
      alert('로그인에 실패했습니다.');
  }
}
  return (
    <div className="login">
      <div className="login_wrapper">
        <div id="container" className={`container ${isSignIn ? 'sign-in' : 'sign-up'}`}>
          <div className="login_row">
            {/* ===================================== 회원가입 ===================================== */}
            <div className="login_col align-items-center flex-col sign-up">
              <div className="form-wrapper align-items-center">
                <div className="form sign-up">
                <LoginTitle src={'img/logo.png'}></LoginTitle>
                <form onSubmit={signupSubmit}>
                  <div className="input-group">
                    <i className="bx bxs-user"></i>
                    <input type="text" placeholder="이름" onChange={e => setName(e.target.value)}/>
                  </div>
                  <div className="input-group">
                    <i className="bx bxs-user"></i>
                    <input type="text" placeholder="닉네임" onChange={e => setNickname(e.target.value)}/>
                  </div>
                  <div className="input-group">
                    <i className="bx bx-mail-send"></i>
                    <input type="email" placeholder="이메일" onChange={e => setEmail(e.target.value)} />
                  </div>
                  <div className="input-group">
                    <i className="bx bxs-lock-alt"></i>
                    <input type="password" placeholder="비밀번호" onChange={e=>setPassword(e.target.value)}/>
                  </div>
                  <div className="input-group">
                    <i className="bx bxs-lock-alt"></i>
                    <input type="password" placeholder="비밀번호 확인" onChange={e=>setConfirmPassword(e.target.value)}/>
                  </div>
                  <div className="input-group">
                    <i className="bx bxs-lock-alt"></i>
                    <input type="tel" placeholder="전화번호" onChange ={ e=>setPhoneNum ( e.target.value )}/>
                  </div>
                  <div className="input-group">
                    <i className="bx bxs-lock-alt"></i>
                    <input type="date" placeholder="생일" onChange ={ e=>setBirthDate ( e.target.value )}/>
                  </div>
                  <div className="gender-group">
                    <i className="bx bxs-lock-alt"></i>
                    <div>
                      <label for="male">남성</label>
                      <input type="radio" name="gender" id="male" onChange ={()=>setGender('남성')}/>
                    </div>
                    <div>
                      <label for="female">여성</label>
                      <input type="radio" name="gender" id="female" onChange={()=>setGender('여성')}/>
                    </div>
                  </div>

                  <button onClick={handleSignUpClick}>Sign up</button>
                </form>
                  <p>
                    <span>Already have an account?</span>
                    <b onClick={handleToggle} className="pointer">
                      Sign in here
                    </b>
                  </p>
                </div>
              </div>
            </div>
            {/* ===================================== 로그인 ===================================== */}
            <div className="login_col align-items-center flex-col sign-in">
              <div className="form-wrapper align-items-center">
                <div className="form sign-in">
                <LoginTitle src={'img/logo.png'}></LoginTitle>
                <form onSubmit={signinSubmit}>
                  <div className="input-group">
                    <i className="bx bxs-user"></i>
                    <input type="email" placeholder="이메일" onChange={(e) => setloginEmail(e.target.value)}/>
                  </div>
                  <div className="input-group">
                    <i className="bx bxs-lock-alt"></i>
                    <input type="password" placeholder="비밀번호" onChange={(e) => setloginPassword(e.target.value)}/>
                  </div>
                  {/* <Link to={"/calendar"} style={{ textDecoration: 'none' }}> */}
                    <button>Sign in</button>
                  {/* </Link> */}
                </form>
                  <SocialContent>
                        <GoogleBtn src={'img/google.png'}></GoogleBtn>
                        <NaverBtn src={'img/naver.png'}></NaverBtn>
                        <KakaoeBtn src={'img/kakao.png'} onClick={loginHandler}></KakaoeBtn>
                    </SocialContent>
                  <p>
                    <b>Forgot password?</b>
                  </p>
                  <p>
                    <span>Don't have an account?</span>
                    <b onClick={handleToggle} className="pointer">
                      Sign up here
                    </b>
                  </p>
                </div>
              </div>
              <div className="form-wrapper"></div>
            </div>
          </div>
          <div className="login_row content-row">
            <div className="login_col align-items-center flex-col">
              <div className="text sign-in">
                <h2>Welcome</h2>
              </div>
              <div className="img sign-in"></div>
            </div>
            <div className="login_col align-items-center flex-col">
              <div className="img sign-up"></div>
              <div className="text sign-up">
                <h2>Join with us</h2>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

export default Login;
profile
개발 기록장

0개의 댓글