[ react ] 저장된 accessToken 가져오기 (replace() 함수)

Suji Kang·2023년 10월 17일
0
post-custom-banner

🐾 저장된accessToken 가져오기

  1. 리액트가 로그인 요청

  2. 익스프레스가 요청을 받아서 mysql에서 존재하는지 확인
    존재하면 jwt 토큰을 생성해서(시간제약 가능) 리액트에게 전달

  3. 리액트는 jwt 토큰을 받아서

    • 로컬스토리지(브라우저) 에 저장
    • 전역 state변수(어떤 컴포넌트에서든 쓸수있는 state변수) 에 저장

📌 로그인 된상태: localstorage 에 jwt 토큰이 존재하는 상태
전역 state 변수에도 저장되어 있음
📌 로그인 안된 상태: localstorage 와 전역 state변수에 jwt 토큰이 저장되지 않는 상태
📌 토큰이 저장되었지만 만료된상태(로그인 시간이 오래되어서)
📌 대시보드 레이아웃은 로그인 한 사람만 봐야한다 (권한존재)


🐾 front에서 server로 데이터 넘기기

📌 GET요청의 경우에는 주소에다가 데이터를 전달한다.

1. 쿼리스트링

📝 "?" 물음표 이후는 "변수"

**리액트에서**
'/api/users' GET요청하면 👉 회원전체 조회야 
**익스프레스 주소**
'/api/users?lastName=김' 회원 김씨 조회야 하고 👉 김씨인사람만 조회, 응답함.
//ex) get요청 검색을 할경우 (search로 get요청) 안녕을 검색할경우 -> 물음표 뒤에 "?q=안녕"

**리액트에서**
'/api/users?lastName=김' GET요청하면,(회원전체조회하고싶은데 성씨가 김씨인사람만 전체조회하고싶다.)
**익스프레스 주소**
'/api/users?lastName=강' 회원 강씨 조회야 하고 👉 강씨인사람만 조회, 응답함.

📌 이렇게 하나씩 다 쓸거야????? =-> NO! 이건 너무 비효율적이야

'/api/users?lastName=김&firstName=철수' GET요청하면 👉 김철수인사람만 조회

2. 파라미터(시멘틱) - ("각각을 유일하게 구분할수 있을때") - 이메일을 겹칠수가없다.

/api/users/abc@naver.com?aaa=김철수
/api/users/test@naver.com

/api/users/:email

/api/users?email=abc@naver.com GET요청의 경우에는 주소에다가 데이터를 넘긴다

둘중에 무엇을사용해야하나? 👉 취향차이

🐾 저장된 토큰 가져오기

login.js

  const { setAccessToken } = useContext(UserContext);

header 는 객체이다 (key 와 value가 있다)
그중에서 Authorization 키값이 있어서 거기에 토큰을 넣어 전달할것이다.
토큰을 전역변수에도 넣어 저장하고 , 로컬스토리지에도 해놓음.

🔎 state변수에 저장한것

헤더도 객체
주소로 보내지않고 헤더로 받아온다
헤더같은 경우는 정보를 받아온다.
토큰을 보내줄때 토큰을 그냥 보내지않고 앞에 암호처럼 Bearer을 붙여서온다 (이건 그냥 이렇게 정해진거다)

header.js

import { useContext, useEffect } from "react";
import { UserText } from "../../styles/common/aside.styles";
import { Header } from "../../styles/common/header.styles";
import axios from "axios";
import { UserContext } from "../../App";

const DashboardHeader = () => {
  //전역state 변수에 있는 토큰 값 가져오기 (login.js에서 설정한 accessToken)
  const { accessToken } = useContext(UserContext);

  //header가 그려지면 db가서 로그인 한 사람 정보 가져오기
  useEffect(() => {
    axios.get('/api/loggedInEmail', 
              { headers: { Authorization: `Bearer ${accessToken}` }}); 
// header안에 문자열을 전달해줘 (Bearer 뒤에 한칸 띄어쓰기)
    // axios.get('/api/users/로그인한사람id')
  }, []);
  return (
    <Header>
      <UserText>강수지<span></span></UserText>
      <i class="fa-solid fa-bars menu-icon"></i>
    </Header>
  );
}

export default DashboardHeader;

이렇게 Bearer에 null 이 들어간것을 볼수있다.
지금 현재는 accecss token는 null 이기때문에.
새로고침하면 사라지기때문에 null이 나옴

🔎 localstorage에 저장한것 1:48

header.js

useEffect(() => {
   axios.get('/api/loggedInEmail', 
             { headers: { Authorization: `Bearer ${localStorage.getItem(accessToken)}` }}); 

app.js

const jwt = require("jsonwebtoken");

//token을 전달받아서 로그인한 사람의 email 주소를 되돌려주는 api
app.get('/api/loggedInEmail', (req, res) => {
    //리액트로부터 전달받은 토큰이 정삭적인지 확인하고
    //정상적이지 않으면 오류로 응답
    //정상적이면 email주소로 응답
    //토큰은 요청 header의 Authorization에 Bearer 토큰값
      // console.log(req.headers.authorization)
  // 문자열로 받음
  const token = req.headers.authorization.replace('Bearer ', '');
  // console.log(token);
  // token은 로그인 당시 발급 받은 토큰

  try{
    let result = jwt.verify(token, process.env.JWT_SECRET);
    // console.log(result);
  
    res.send(result.email);

  }catch(err){
    console.log(err);
    res.status(403).json('오류발생!');
  }
});

.env.local 설정해주고,

JWT_SECRET=board23
🌟 console.log(req.headers.authorization) 

👇
결과값?



<const token = req.headers.authorization.replace('Bearer ', ''); //순수 토큰 발급됨 앞에 Bearer 빠지고 ->관리차원에서 이렇게 나옴.

📝 replace() 함수

replace() 함수는 문자열에서 특정 문자 또는 패턴을 찾아 다른 문자열로 대체할 때 사용됩니다

let originalString = "Hello, World! Hello, Universe!";
let newString = originalString.replace("Hello", "Hi");
//hello를 hi로 바꿔줘

console.log(newString);
//"Hi, World! Hello, Universe!"

🔎 header가 그려지면 db가서 로그인 한 사람 정보 가져오기 (전역state 변수에 있는 토큰 값 가져오기 )
header.js

import { useContext, useEffect } from "react";
import { UserText } from "../../styles/common/aside.styles";
import { Header } from "../../styles/common/header.styles";
import axios from "axios";
import { UserContext } from "../../App";

const DashboardHeader = () => {
  //전역state 변수에 있는 토큰 값 가져오기 (login.js에서 설정한 accessToken)
  const { accessToken } = useContext(UserContext);

  //header가 그려지면 db가서 로그인 한 사람 정보 가져오기
  useEffect(() => {
    axios.get('/api/loggedInEmail', { headers: { Authorization: `Bearer ${accessToken}` } }); // header안에 문자열을 전달해줘 (Bearer 뒤에 한칸 띄어쓰기)
    // axios.get('/api/users/로그인한사람id')
  }, []);
  return (
    <Header>
      <UserText>강수지<span></span></UserText>
      <i class="fa-solid fa-bars menu-icon"></i>
    </Header>
  );
}

export default DashboardHeader;

app.js 2:20

app.get('/api/users/:email', async (req, res) => { //:email 이라고 쓰면 email이라는 변수로 사용가능 (동적으로 요청)
    // console.log(req.params);
    const email = req.params.email;
    let sql = `
    SELECT email, created_date, updated_date, profile_url, cover_url
    from tbl_users
    WHERE email = ?
  `;
    try {
        let [rows, fields] = await pool.query(sql, [email]);
        res.json(rows[0]);
    } catch (err) {
        res.status(500).json('서버 오류 발생');
    }
});

rows[0]->객체로 받아서 보내준다.

header.js

import { useContext, useEffect, useState } from "react";
import { Header } from "../../styles/common/header.styles";
import axios from "axios";
import { UserContext } from "../../App";
import { useNavigate } from "react-router-dom";


const DashboardHeader = () => {
  const navigate = useNavigate();
  // 전역state변수에 있는 토큰 값 가져오기
  const { accessToken } = useContext(UserContext);
  const [loggedInEmail , setLoggedInEmail] = useState('로그인후 이용해주세요');

  // 헤더가 그려지면 db가서 로그인 한 사람 정보 가져오기
  useEffect(() => {

    let tmp = async () => {
      try {
        let res = await axios.get('/api/loggedInEmail',
          { headers: { Authorization: `Bearer ${localStorage.getItem('accessToken')}` } }
        );

        // res.data에 로그인한 사람 이메일 주소가 들어있음
        let res2 = await axios.get(`/api/users/${res.data}`);
        //console.log(res2.data);
        setLoggedInUser(res2.data);
      } catch (err) {
        // 로그인 시간이 만료되거나 로그인을 안한 경우
        console.log(err);
        alert('로그인을 먼저 해주셔야 이용하실 수 있습니다');
        navigate('/login', { replace: true });
      }
    }

    tmp();
    // axios.get('/api/users/로그인한사람id');
  }, [navigate]);// 의존성으로 넣어줘야함

  return (
    <Header>
      <UserText>{loggedInEmail}<span></span>
      </UserText>
    </Header>
  );
}

export default DashboardHeader;

🔎 클릭하면, 내가 언제 회원가입했는지, 언제 업데이트수정했는지 나오게하기

import { useContext, useEffect, useState } from "react";
import { UserText } from "../../styles/common/aside.styles";
import { Header } from "../../styles/common/header.styles";
import axios from "axios";
import { UserContext } from "../../App";
import { useNavigate } from "react-router-dom";
import MenuIcon from '@mui/icons-material/Menu';
import MenuOpenIcon from '@mui/icons-material/MenuOpen';
import { Popover } from "@mui/material";

const DashboardHeader = () => {
  const navigate = useNavigate();
  // 전역state변수에 있는 토큰 값 가져오기
  const {accessToken, setAccessToken} = useContext(UserContext);
  const [loggedInUser, setLoggedInUser] = useState({
    email: '로그인후 이용해주세요',
    created_date: '',
    updated_date: ''
  });
  // const [loggedInEmail , setLoggedInEmail] = useState('로그인후 이용해주세요');

  // popOver 창의 기준 element 요소
  const [anchorEl, setAnchorEl] = useState(null);
  let open = Boolean(anchorEl);

  // 헤더가 그려지면 db가서 로그인 한 사람 정보 가져오기
  useEffect(() => {

    let tmp = async () => {
      try {
        let res = await axios.get('/api/loggedInEmail',
          { headers: { Authorization: `Bearer ${localStorage.getItem('accessToken')}` } }
        );

        // res.data에 로그인한 사람 이메일 주소가 들어있음
        let res2 = await axios.get(`/api/users/${res.data}`);
        console.log(res2.data);
        setLoggedInUser(res2.data);


      } catch (err) {
        // 로그인 시간이 만료되거나 로그인을 안한 경우
        console.log(err);
        alert('로그인을 먼저 해주셔야 이용하실 수 있습니다');
        navigate('/login', { replace: true });
      }
    }

    tmp();
    // axios.get('/api/users/로그인한사람id');
  }, [navigate]);

  const onLogout = () => {
    //로그아웃 버튼이 클릭되면 토큰을 삭제
    //localStorage 에 저장된 토큰을 삭제 
    localStorage.removeItem('accessToken');
    //전역 상태변수에 저장된 토큰도 삭제
    setAccessToken(null);
    navigate('/login', { replace: true });
  }

  return (
    <Header>
      <div>
        <UserText onClick={(e) => { setAnchorEl(e.currentTarget) }}>{loggedInUser.email}<span></span></UserText>
        <Popover
          anchorEl={anchorEl}
          open={open}
          onClose={() => { setAnchorEl(null) }}
          anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}
        >
          <p>회원가입일 : {loggedInUser.created_date}</p>
          <p>마지막수정일: {loggedInUser.updated_date}</p>
          <button onClick={onLogout}>로그아웃</button>
        </Popover>
      </div>
      <MenuOpenIcon />
    </Header>
  );
}

export default DashboardHeader;

🔎 로그아웃하기 - 토큰을 삭제하기(전역변수, localstorage모두 삭제)

import { useContext, useState } from "react";
import { UserContext } from "../../App";
import { useNavigate } from "react-router-dom";
const {accessToken, setAccessToken} = useContext(UserContext);

const onLogout = () => {
    //로그아웃 버튼이 클릭되면 토큰을 삭제
    //localStorage 에 저장된 토큰을 삭제 
    localStorage.removeItem('accessToken');
    //전역 상태변수에 저장된 토큰도 삭제
    setAccessToken(null);
    navigate('/login', { replace: true });
  }

return (
    <Header>
      <div>
        <UserText onClick={(e) => { setAnchorEl(e.currentTarget) }}>{loggedInUser.email}<span></span></UserText>
        <Popover
          anchorEl={anchorEl}
          open={open}
          onClose={() => { setAnchorEl(null) }}
          anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}
        >
          <p>회원가입일 : {loggedInUser.created_date}</p>
          <p>마지막수정일: {loggedInUser.updated_date}</p>
          <button onClick={onLogout}>로그아웃</button>
        </Popover>
      </div>
      <MenuOpenIcon />
    </Header>
  );
}
profile
나를위한 노트필기 📒🔎📝
post-custom-banner

0개의 댓글