github oauth
- 깃허브로 로그인 버튼 클릭
- Oauth 인증
- 인증 완료시 authorization code와 함께 callback url로 리디렉션
- 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) => {
console.log(req.body);
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) => {
if (!req.headers.authorization) {
res.status(403).send({
message: 'no permission to access resources'
})
return;
}
res.status(200).send({ images })
}