sprint - auth_oauth

FeelSoo·2022년 5월 18일
0

CodeStates

목록 보기
39/43

< work flow >

1) Github - Settings - Developer settings - OAuth Apps - New OAuth App 클릭하여 OAuth를 통한 로그인 정보작성

Authorization callback URL :

OAuth 메커니즘이 인증 과정이 끝난 후 리디렉션을 통해 다시 내 앱으로 이동하는 원리이므로, 내 앱으로 돌아가기 위한 Authorization callback URL이 필요

https://www.oauth.com/oauth2-servers/accessing-data/create-an-application/




2) .env 에 깃허브에서 받은 client ID 와 secret 를 기입

GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=





3) Access Token 요청

https://docs.github.com/en/developers/apps/building-github-apps/identifying-and-authorizing-users-for-github-apps#2-users-are-redirected-back-to-your-site-by-github

server-oauth/controller/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 = async (req, res) => {

    // req의 body로 authorization code가 들어옵니다. console.log를 통해 서버의 터미널창에서 확인해보세요!
  console.log(req.body);

   // TODO : 이제 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


    // req의 body로 authorizationCode가 들어온다.
    // authorizationCode로 access token을 발급한다.
    try {
      const result = await axios.post(
        'https://github.com/login/oauth/access_token', 
        {
          client_id: clientID,
          client_secret: clientSecret,
          code: req.body.authorizationCode
        }, 
        { headers: { accept: 'application/json' } }
      );
      const accessToken = result.data.access_token;
      res.json({ accessToken });
    } catch (err) {
      console.log(err);
      res.sendStatus(404);
    }
  };





4 ) 이미지 반환

server-oauth/controller/images.js

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

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

  console.log(req.headers);
    
    if (req.headers.authorization) {
        res.send({ images: images });
    } else {
        console.log(res.body);
        res.status(403).send({ message: "no permission to access resources" });
    }
}




< CLIENT >

  1. client-oauth/src/App.js

authorizationCode 받아오면 axios로 서버에 액세스 토큰받아오게 요청.

서버의 callback.js 파일과 연관되는 부분

액세스토큰 받아오면 setState로 상태 업데이트


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: ""
    // TODO:
  };
  this.getAccessToken = this.getAccessToken.bind(this);
}

async getAccessToken(authorizationCode) {
  // 받아온 authorization code로 다시 OAuth App에 요청해서 access token을 받을 수 있습니다.
  // access token은 보안 유지가 필요하기 때문에 클라이언트에서 직접 OAuth App에 요청을 하는 방법은 보안에 취약할 수 있습니다.
  // authorization code를 서버로 보내주고 서버에서 access token 요청을 하는 것이 적절합니다.

  // TODO: 서버의 /callback 엔드포인트로 authorization code를 보내주고 access token을 받아옵니다.
  // access token을 받아온 후
  //  - 로그인 상태를 true로 변경하고,
  //  - state에 access token을 저장하세요

  const accessToken = await axios.post("http://localhost:8080/callback", {
    authorizationCode
  });
  console.log(accessToken);
  this.setState({
    isLogin: true,
    accessToken: accessToken.data.accessToken
  });
}


componentDidMount() {
  const url = new URL(window.location.href)
  const authorizationCode = url.searchParams.get('code')
  if (authorizationCode) {
    // authorization server로부터 클라이언트로 리디렉션된 경우, authorization code가 함께 전달됩니다.
    // ex) http://localhost:3000/?code=5e52fb85d6a1ed46a51f
    this.getAccessToken(authorizationCode)
  }
}



render() {
  const { isLogin, accessToken } = this.state;
  return (
    <Router>
      <div className='App'>
      {isLogin ? <Mypage accessToken={accessToken} /> : <Login />}
      </div>
    </Router>
  );
}
}

export default App;



  1. client-oauth/src/components/Login.js -- 깃허브 인증 페이지로 이동하게 코드작성
import React, { Component } from 'react';

class Login extends Component {
constructor(props) {
  super(props)

  this.socialLoginHandler = this.socialLoginHandler.bind(this)

  // TODO: GitHub로부터 사용자 인증을 위해 GitHub로 이동해야 합니다. 적절한 URL을 입력하세요.
  // OAuth 인증이 완료되면 authorization code와 함께 callback url로 리디렉션 합니다.
  // 참고: https://docs.github.com/en/free-pro-team@latest/developers/apps/identifying-and-authorizing-users-for-github-apps

  this.GITHUB_LOGIN_URL = `https://github.com/login/oauth/authorize?client_id=db55da56ae18e3532465`;
}

socialLoginHandler() {
  window.location.assign(this.GITHUB_LOGIN_URL)
}

render() {
  return (
    <div className='loginContainer'>
      OAuth 2.0으로 소셜 로그인을 구현해보세요.
      <img id="logo" alt="logo" src="https://cdn-icons-png.flaticon.com/512/25/25231.png" />
      <button
        onClick={this.socialLoginHandler}
        className='socialloginBtn'
      >
        Github으로 로그인
        </button>
    </div>
  );
}
}

export default Login;



  1. client-oauth/src/components/Mypage.js

유저정보를 받아오는 axios작성

이미지 받아오는 axios 작성해서 각각 상태를 업데이트 해주면된다

import React, { Component } from "react";
import axios from 'axios';
const FILL_ME_IN = 'FILL_ME_IN'

class Mypage extends Component {

constructor(props) {
  super(props);
  this.state = {
    images: [],
    name: "",
    login: "",
    html_url: "",
    public_repos: ""
    // TODO: GitHub API 를 통해서 받아올 수 있는 정보들 중에서
    // 이름, login 아이디, repository 주소, public repositoty 개수를 포함한 다양한 정보들을 담아주세요.
  }
}

async getGitHubUserInfo() {
  const user = await axios.get(`https://api.github.com/user`, {
    headers: { authorization: `token ${this.props.accessToken}` }
  });
  // console.log(user);
  this.setState({
    name: user.data.name,
    login: user.data.login,
    html_url: user.data.html_url,
    public_repos: user.data.public_repos
  });
  // TODO: GitHub API를 통해 사용자 정보를 받아오세요.
  // https://docs.github.com/en/free-pro-team@latest/rest/reference/users#get-the-authenticated-user
}

async getImages() {
  const getImg = await axios.get(`http://localhost:8080/images`, {
    headers: { authorization: `token ${this.props.accessToken}` }
  });
  this.setState({
    images: getImg.data.images
  });
  // TODO : 마찬가지로 액세스 토큰을 이용해 local resource server에서 이미지들을 받아와 주세요.
  // resource 서버에 GET /images 로 요청하세요.
}

componentDidMount() {
  this.getGitHubUserInfo()
  this.getImages()
}

render() {
  const { accessToken } = this.props

  if (!accessToken) {
    return <div>로그인이 필요합니다</div>
  }

  return (
    <div>
      <div className='mypageContainer'>
        <h3>Mypage</h3>
        <hr />

        <div>안녕하세요. <span className="name" id="name">{this.state.name}</span>님! GitHub 로그인이 완료되었습니다.</div>
        <div>
          <div className="item">
            나의 로그인 아이디:
            <span id="login">{this.state.login}</span>
          </div>
          <div className="item">
            나의 GitHub 주소:
            <span id="html_url">{this.state.html_url}</span>
          </div>
          <div className="item">
            나의 public 레포지토리 개수:
            <span id="public_repos">{this.state.public_repos}</span>개수
          </div>
        </div>

        <div id="images">
        {this.state.images.map((img, i) => {
            return <img key={i} src={img.blob} alt={img.file} />;
          })}
          {/* TODO: 여기에 img 태그를 이용해 resource server로 부터 받은 이미지를 출력하세요 */}
        </div>
      </div>
    </div >
  );
}

}

export default Mypage;
profile
세상은 넓고 배울건 많다

0개의 댓글