HTTPS - 토큰 기반 인증 실습(Client)

김도영·2022년 6월 8일
0

App.js

import React, { Component } from "react";

import Login from "./components/Login";
import Mypage from "./components/Mypage";

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isLogin: false,
      accessToken: "",
    };

    this.loginHandler = this.loginHandler.bind(this);
    this.issueAccessToken = this.issueAccessToken.bind(this);
  }

  
  loginHandler(data) { // 로그인의 상태 변동
    this.setState({isLogin: true})
  }

  issueAccessToken(token) { // 토큰의 값을 변경
    this.setState({accessToken: token})
  }

  render() {
    const { isLogin } = this.state;
    return (
      <div className='App'>
        {/* isLogin 상태에 따라 Mypage 혹은 Login 컴포넌트를 삼항 연산자로 Mypage와 Login 렌더링*/}
  		{/* Mypage는 refreshtoken으로 accesstoken 다시 생성*/}
		{/* Login은 issueAccessToken과 loginHandler를 내려준다.*/}
        {isLogin ?
        <Mypage accessToken={this.state.accessToken} issueAccessToken={this.issueAccessToken} /> :
        <Login loginHandler={this.loginHandler} issueAccessToken={this.issueAccessToken} />}
      </div>
    );
  }
}

export default App;

components/Login.js

import axios from "axios";
import React, { Component } from "react";

class Login extends Component {
  constructor(props) {
    super(props);
    this.state = {
      userId: "",
      password: "",
    };
    this.inputHandler = this.inputHandler.bind(this);
    this.loginRequestHandler = this.loginRequestHandler.bind(this);
  }

  inputHandler(e) {
    this.setState({ [e.target.name]: e.target.value });
  }

  loginRequestHandler() {
    /*
    Login 컴포넌트가 가지고 있는 state를 이용해 로그인을 구현
    로그인을 담당하는 api endpoint에 요청을 보내고, 받은 데이터로 상위 컴포넌트 App의 state를 변경
    초기 App:
    state = { isLogin: false, accessToken: "" }
    로그인 요청 후 App:
    state = { isLogin: true, accessToken: 서버에_요청하여_받은_access_token }
    */
    axios.post('https://localhost:4000/login', {
      userId: this.state.userId,
      password: this.state.password
    })
    // 로그인 요청시, 아이디와 비밀번호를 같이 보내주고 res를 받고 난 뒤
    // accesstoken을 App.js에 보내준다.
    .then( res => {
      this.props.issueAccessToken(res.data.data.accessToken)
      this.props.loginHandler(res.data.data.accessToken)
    })
  }

  render() {
    return (
      <div className='loginContainer'>
        <div className='inputField'>
          <div>Username</div>
          <input
            name='userId'
            onChange={(e) => this.inputHandler(e)}
            value={this.state.userId}
            type='text'
          />
        </div>
        <div className='inputField'>
          <div>Password</div>
          <input
            name='password'
            onChange={(e) => this.inputHandler(e)}
            value={this.state.password}
            type='password'
          />
        </div>
        <div className='loginBtnContainer'>
          <button onClick={this.loginRequestHandler} className='loginBtn'>
            JWT Login
          </button>
        </div>
      </div>
    );
  }
}

export default Login;

Components/Mypage.js

import axios from "axios";
import React, { Component } from "react";

class Mypage extends Component {
  constructor(props) {
    super(props);
    this.state = {
      userId: "",
      email: "",
      createdAt: "",
    };
    this.accessTokenRequest = this.accessTokenRequest.bind(this);
    this.refreshTokenRequest = this.refreshTokenRequest.bind(this);
  }

  accessTokenRequest() {
    /* 
    상위 컴포넌트인 App에서 받은 props를 이용해 accessTokenRequest 메소드를 구현
    access token을 처리할 수 있는 api endpoint에 요청을 보내고, 받은 데이터로 Mypage 컴포넌트의 state (userId, email, createdAt)를 변경
    초기 Mypage:
    state = { userId: "", email: "", createdAt: "" }
    accessTokenRequest 후 Mypage:
    state = { userId: "특정유저id", email: "특정유저email", created: "특정유저createdAt" }
    
    ** 주의사항 **
    App 컴포넌트에서 내려받은 accessToken props를 authorization header에 담아 요청을 보내야 한다.
    */
   
   // accessTokenRequest는 accesstoken으로 get 요청을 보내
   // 토큰이 갖고 있던 데이터를 Mypage state의 userInfo로 넣어준다.
    axios.get('https://localhost:4000/accesstokenrequest', {
      headers: {authorization: `Bearer ${this.props.accessToken}`}
    })
    .then( res => {
      this.setState({
        ...res.data.data.userInfo
      })
    })
  }

  refreshTokenRequest() {
    /*
    쿠키에 담겨져 있는 refreshToken을 이용하여 refreshTokenRequest 메소드를 구현
    refresh token을 처리할 수 있는 api endpoint에 요청을 보내고, 받은 데이터로 2가지를 구현
    1. Mypage 컴포넌트의 state(userId, email, createdAt)를 변경
    2. 상위 컴포넌트 App의 state에 accessToken을 받은 새 토큰으로 교환
    */
   
    //refreshTokenRequest는 새로 acceesstoken을 발급 받는 컴포넌트
    axios.get('https://localhost:4000/refreshtokenrequest')
    .then( res => {
      this.setState({
        ...res.data.data.userInfo
      })
      this.props.issueAccessToken(res.data.data.accessToken)
    })
  }

  render() {
    const { userId, email, createdAt } = this.state;
    return (
      <div className='mypageContainer'>
        <div className='title'>Mypage</div>
        <hr />
        <br />
        <br />
        <div>
          안녕하세요. <span className='name'>{userId ? userId : "Guest"}</span>! jwt 로그인이
          완료되었습니다.
        </div>
        <br />
        <br />
        <div className='item'>
          <span className='item'>나의 이메일: </span> {email}
        </div>
        <div className='item'>
          <span className='item'>나의 아이디 생성일: </span> {createdAt}
        </div>
        <br />
        <br />
        <div className='btnContainer'>
          <button className='tokenBtn red' onClick={this.accessTokenRequest}>
            access token request
          </button>
          <button className='tokenBtn navy' onClick={this.refreshTokenRequest}>
            refresh token request
          </button>
        </div>
      </div>
    );
  }
}

export default Mypage;
profile
Blockchain Developer

0개의 댓글