oauth


github oauth
ログインボタン
  • をクリックしてハブ
  • に入ります.
  • 認証
  • 認証が完了すると、認証コード付きコールバックURL
  • にリダイレクトする.
  • App.jsで構成部品をレンダリングするたびにurlにコードパラメータがあるかどうかを確認する場合は、認証コードをサーバに送信し、サーバからトークンへのアクセスを要求します.
    (クライアントから直接OAuthアプリケーションにアクセストークンを要求するセキュリティが劣るため、サーバが要求することが望ましい)
  • .
    クライアント
    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 })
    }