oauth

Creating the dots·2021년 10월 22일
0

Authentication

목록 보기
3/3

github oauth

  1. 깃허브로 로그인 버튼 클릭
  2. Oauth 인증
  3. 인증 완료시 authorization code와 함께 callback url로 리디렉션
  4. App.js에서 컴포넌트가 렌더링될때마다 url에 code 파라미터가 있는지 확인하고 있다면 authorization code를 서버로 보내주고, 서버에서 access token 요청
    (클라이언트에서 직접 OAuth App에 access token을 요청하는 것은 보안에 취약하므로 서버에서 요청하도록 하는 것이 적절)

클라이언트

App.js

import React, { Component } from "react";
import { BrowserRouter as Router } from "react-router-dom";
import Login from "./components/Login";
import Mypage from "./components/Mypage";
import axios from "axios";

class App extends Component{
  constructor(){
    super();
    this.state = {
      isLogin: false,
      accessToken:"",
    };
    this.getAccessToken = this.getAccessToken.bind(this);
  }
  
  async getAccessToken(authorizationCode){
    await axios({
      url:"https://localhost:8080/callback",
      method:"post",
      data: {
        authorizationCode,
      },
    })
    .then((res) => {
      this.setState({isLogin: true, accessToken: res.data.accessToken})
    })
    .catch((err)=>{
      console.log(err);
    })
  }
  componentDidMount(){
    const url = new URL(window.location.href);
    const authorizationCode = url.searchParams.get("code");
    if(authorizationCode){
      this.getAccessToken(authorizationCode);
    }
  }
  
  render(){
    const {isLogin, accessToken} = this.state;
    return(
      <Router>
        <div className="App">
          {isLogin? <Mypage accessToken={accessToken} /> : <Login />}
        </div>
      </Router>
	)
  }
}
export default App;           

Login.js

import React, {Component} from "react";

class Login extends Component {
  constructor(props){
    super(props);
    this.socialLoginHandler = this.socialLoginHandler.bind(this);
    this.GITHUB_LOGIN_URL = "https://github.com/login/oauth/authorization?client_id="클라이언트 아이디";
    socialLoginHandler(){
      window.location.assign(this.GITHUB_LOGIN_URL);
    }
    
    render(){
      return(
        <div className="loginContainer">
        OAuth 2.0으로 소셜 로그인을 구현해보세요.
        <img id="logo" alt="logo" src="https://image.flaticon.com/icons/png/512/25/25231.png" />
        <button onClick={this.socialLoginHandler} className="socialloginBtn">
        </button>
    </div>
    );
  }
}
export default Login;    

Mypage.js

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

class Mypage extends Component {
  constructor(props){
    super(props);
    this.state = {
      images:[],
      name:"",
      login:"",
      html_url:"",
      public_repos:0,
    }
  }
  
  async getGitHubUserInfo(){
    let response = axios({
      url: "https://apli.github.com/user",
      method: "get",
      headers: {
        authorization: `token ${this.props.accessToken}`,
      },
    });
    const {name, login, html_url, public_repos} = response.data;
    
    this.setState({
      name, 
      login, 
      html_url, 
      public_repos
    });
  }
  
  async getImages(){
    const {accessToken} = this.props;
    let response = await axios({
      url: "http://localhost:8080/images",
      method:"get",
      headers: {
        authorization: `token ${accessToken}`,
      }
    });
    
    const {images} = reponse.data;
    
    this.setState({
      images
    })
  }
  
  componentDidMount(){
    this.getGitHubUserInfo();
    this.getImages();
  }
  
  render(){
    const {accessToken} = this.props;
    if(!accessToken){
      return <div>로그인이 필요합니다</div>
    }
    
    const {name, login, html_url, public_repos, images} = this.state;
    return (
      <div>
      <div className="mypageContainer">
      <h3>Mypage</h3>
      <hr />
      
      <div>안녕하세요. <span className="name" id="name">{name}</span>! Github 로그인이 완료되었습니다</div>
      <div>
            <div className="itme">나의 로그인 아이디:<span id="login">{login}</span></div>
            <div className="item">나의 GitHub 주소:
              <span id="html_url">{html_url}</span></div>
            <div className="item">
              나의 public 레포지토리 개수:
              <span id="public_repos">{public_repos}</span></div>
      </div>
	  <div id="images">
            {
              images.map(img => <img key={img.file} src={img.blob} />)
            }
          </div>
        </div>
      </div >
    );
}
export default Mypage;

서버

callback.js

require('dotenv').config();

const clientID = process.env.GITHUB_CLIENT_ID;
const clientSecret = process.env.GITHUB_CLIENT_SECRET;
const axios = require('axios');

module.exports = (req, res) => {
  //req의 body로 authorization code가 들어온다. 
  console.log(req.body);

  //이제 authorization code를 이용해 access token을 발급받기 위한 post 요청을 보낸다.
  //https://docs.github.com/en/free-pro-team@latest/developers/apps/identifying-and-authorizing-users-for-github-apps#2-users-are-redirected-back-to-your-site-by-github

  axios({
    method: 'post',
    url: `https://github.com/login/oauth/access_token`,
    headers: {
      accept: 'application/json',
    },
    data: {
      client_id: clientID,
      client_secret: clientSecret,
      code: req.body.authorizationCode
    }
  }).then((response) => {
    accessToken = response.data.access_token;
    res.status(200).json({ accessToken: accessToken })

  }).catch(e => {
    res.status(404)
  })
}

images.js

const images = require('../resources/resources');

module.exports = (req, res) => {
  //Mypage로부터 access token을 제대로 받아온 것이 맞다면, resource server의 images를 클라이언트로 보낸다

  if (!req.headers.authorization) {
    res.status(403).send({
      message: 'no permission to access resources'
    })
    return;
  }

  res.status(200).send({ images })
}
profile
어제보다 나은 오늘을 만드는 중

0개의 댓글