실습전에 github 설정을 해야하는데 필요한 코드는 다음 블로그 포스팅을 참고하면 된다.
다음은 Github OAuth 와 노드JS를 연동하는 코드다.
GITHUB_CLIENT_ID="설정"
GITHUB_CLIENT_SECRET="설정"
import React, { Component } from "react";
class Login extends Component {
constructor(props) {
super(props);
this.socialLoginHandler = this.socialLoginHandler.bind(this);
// 참고: 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=클라이언트id";
}
//
// Window Location Assign
// location.assign() 함수는 새로운 페이지를 로드합니다.
// 버튼 클릭 후 GITHUB_LOGIN_URL로 새 패이지를 로드한 뒤 권한요청에 수락한다면
// Authorization code와 함께 같은 url 뒤에 Authorization code를 파라미터로 리디렉션된다.
socialLoginHandler() {
window.location.assign(this.GITHUB_LOGIN_URL);
}
render() {
return (
<div className="loginContainer">
OAuth 2.0으로 소셜 로그인을 구현해보세요.
<img
id="logo"
alt="logo"
src="https://codestates.com/assets/codestates-ci.png"
/>
<button onClick={this.socialLoginHandler} className="socialloginBtn">
Github으로 로그인
</button>
</div>
);
}
}
export default Login;
import React, { Component } from "react";
import axios from "axios";
class Mypage extends Component {
constructor(props) {
super(props);
this.state = {
images: [],
// TODO: GitHub API 를 통해서 받아올 수 있는 정보들 중에서
// 이름, login 아이디, repository 주소, public repositoty 개수를 포함한 다양한 정보들을 담아주세요.
};
}
//리소스를 리퀘스트하는 함수
async getGitHubUserInfo() {
// TODO: GitHub API를 통해 사용자 정보를 받아오세요.
// https://docs.github.com/en/free-pro-team@latest/rest/reference/users#get-the-authenticated-user
const { accessToken } = this.props;
if (!accessToken) {
return;
} else {
console.log("accessToken", accessToken);
const result = await axios({
method: "get",
url: "https://api.github.com/user",
headers: {
authorization: `Bearer ${accessToken}`,
},
});
const { name, login, html_url, public_repos } = result.data;
this.setState({
name, //이름
login, //나의 로그인 아이디
html_url, //깃헙 주소
public_repos, //깃헙 레퍼지토리
});
}
}
async getImages() {
// TODO : 마찬가지로 액세스 토큰을 이용해 local resource server에서 이미지들을 받아와 주세요.
// resource 서버에 GET /images 로 요청하세요.
const { accessToken } = this.props;
if (!accessToken) {
return;
} else {
const result = await axios({
method: "get",
url: "http://localhost:8080/images",
headers: {
Accpet: "application/json",
authorization: `Bearer ${accessToken}`,
},
});
const { images } = result.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="item">
나의 로그인 아이디:
<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">
{/* TODO: 여기에 img 태그를 이용해 resource server로 부터 받은 이미지를 출력하세요 */}
{images.map((img) => (
<img key={img.file} src={img.blob} />
))}
</div>
</div>
</div>
);
}
}
export default Mypage;
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,
// TODO:
accessToken: "",
};
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을 저장하세요
await axios
.post("http://localhost:8080/callback", { authorizationCode })
.then((data) => {
this.setState({
isLogin: true,
accessToken: data.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=$code
this.getAccessToken(authorizationCode);
}
}
render() {
const { isLogin, accessToken } = this.state;
return (
<Router>
<div className="App">
{isLogin ? <Mypage accessToken={accessToken} /> : <Login />}
</div>
</Router>
);
}
}
export default App;
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를 통해 서버의 터미널창에서 확인해보세요!
//인증(authentication)은 자신이 누구라고 주장하는 사람을 확인하는 절차이다. 권한부여(authorization)는 가고 싶은 곳으로 가도록 혹은 원하는 정보를 얻도록 허용하는 과정이다.
console.log(req);
// 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
// 2) AccessToken
//
// 클라이언트에서 받은 Authorization Code를 Authorization Server로 보내고
// Server는 이를 이용해 AccessToken을 발급 받는다.
console.log("req.body.authorizationCode", req.body.authorizationCode);
axios({
method: "post",
url: `https://github.com/login/oauth/access_token`,
headers: {
accept: "application/json",
},
data: {
//oauth 앱등록시 받은 클라이언트 아이디, 클라이언트 시크릿 그리고 클라이언트에서 받은
//req.body.authorizationCode를 가지고 요청을 한다.
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);
});
};
const images = require("../resources/resources");
const express = require("express");
module.exports = (req, res) => {
// TODO : Mypage로부터 access token을 제대로 받아온 것이 맞다면, resource server의 images를 클라이언트로 보내주세요.
console.log(req.headers);
if (!req.headers.authorization) {
res.status(403).send({ message: "no permission to access resources" });
return;
} else {
res.status(200).send({ images });
}
};
출처 : 코드스테이츠
OAuth 2.0(Open Authorization 2.0,) (0) | 2023.01.05 |
---|---|
토큰 기반 인증 - NodeJS (0) | 2023.01.03 |
NodeJS 에서 세션기능 구현하기~! (0) | 2023.01.03 |
세션 기반 인증 - Session-based Authentication (0) | 2023.01.03 |
Stateless를 Stateful하게 만들어주는 Cookie! (0) | 2023.01.02 |