์ ๋ถํฐ ๋๋ฌด๋๋ ํด๋ณด๊ณ ์ถ์๋ ๊นํ๋ธ OAuth ๋ก๊ทธ์ธ์ ์ฑ๊ณต์ ์ผ๋ก ๊ตฌํํ๋ค.
๊ตฌํ๋จ๊ณ์ ๋ฐฉ๋ฒ์ ์ค๋ช ํด๋ณผ ์์ !
๐ ํ๋ก์ ํธ ๊ตฌ์ฑ
* React ํจ์ํ ์ปดํฌ๋ํธ (jsx) ๋ฐฉ์์ผ๋ก ๊ตฌํํ ํ๋ก์ ํธ์ ๋๋ค!
* BE์ ํจ๊ปํ ํ๋ก์ ํธ๋ก BE ๋จ์์๋ access-token ๋ฐ๊ธ๊ณผ ์ ๋ณด ์์ฒญ์ ๋งก์ ์ฒ๋ฆฌํ์ต๋๋ค.
* FE๋จ์์๋ code์์ฒญํํ์ Github ๊ณ์ ์ ๋ณด๋ฅผ ๋ฐ๋ก ์์ฒญํ์ต๋๋ค.
๊นํ๋ธ ๋ก๊ทธ์ธ ๊ตฌํ์ ๊ฒ์ํด๋ณด๋ฉด ๊ตฌํํ๋ ์ฌ๋ฌ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์์ง๋ง ํฌ๊ฒ ๋๊ฐ์ง๋ก ๋๋๋ ๋๋์ ๋ฐ์๊ณ , 2๋ฒ ๋ฐฉ๋ฒ์ผ๋ก ์ฒ๋ฆฌํ๋ค .
1) FE๋จ์์ code ์์ฒญํ ํ POST ๋ก jwt ์์ฒญ : ์ฐธ๊ณ (https://devhyun.com/blog/post/15)
2) โ FE๋จ์์ code ์์ฒญํ ํ GET์ผ๋ก jwt ์์ฒญ (BE์์ POST ์ฒ๋ฆฌ)
๐ ๊ตฌํ ๋จ๊ณ
1) ๊นํ๋ธ์์ Application ๋ฑ๋ก
2) client-id , client-secret ๋ฐ๊ธ๋ฐ๊ธฐ (redirect url ์ค์ )
3) code ๋ฐ๊ธ๋ฐ๊ธฐ
4)access-token ๋ฐ๊ธ๋ฐ๊ธฐ
5)jwt ํ ๊ทผ ๋ฐ๊ธ๋ฐ์ ์ฌ์ฉ
1) ๊นํ๋ธ์์ Application ๋ฑ๋ก
๊นํ๋ธ - settings - Developer settings - OAuth Apps - new OAuth App
2) client-id , client-secret ๋ฐ๊ธ๋ฐ๊ธฐ (redirect url ์ค์ )
new OAuth App์ ์ค์ ํ๊ฒ ๋๋ฉด ์๋์ ๊ฐ์ด URL ์ ๋ ฅ ๋์ด ๋์ค๋๋ฐ
Homepage URL : ํ๋ก์ ํธ web ์ฃผ์
Authorization callback URL : ๊นํ๋ธ ๋ก๊ทธ์ธ ์ redirect ๋ ์ฃผ์
-> ํ์ฌ React๋ก ๊ตฌํ์ค์ด์ด์ ๋ก๊ทธ์ธ์ ์ฒ๋ฆฌํ Component ๋ฅผ ์ฐ๊ฒฐํ Route path๋ฅผ ์ ์ผ๋ฉด ๋๋ค.
ex) <Callback> component์์ ์ฒ๋ฆฌํ ๊ฒฝ์ฐ
<Route path="/callback" component={Callback} />
client secerts๋ ๋ฐ๊ธ ๋น์์ ๋ณด์ฌ์ง๋ ๊ฐ์ธ์ ์ธ ๊ณต๊ฐ์ ๊ธฐ๋กํ๊ณ , ๊ณต๊ฐ๋์ง ์๋๋ก ์ฃผ์ํด์ผ ํ๋ค.
Homepage URL๊ณผ callback URL์ ๋ฐฐํฌ ์ localhost๋ก ์ฌ์ฉํ๋ค ๋ฐฐํฌ ์ ๋ฐฐํฌ ์ฃผ์๋ก ๋ณ๊ฒฝํด์ค์ผ ํ๋ค.
3) code ๋ฐ๊ธ๋ฐ๊ธฐ
ํ๋จ url ์ code GET์์ฒญ ๋ณด๋ด๊ธฐ
https://github.com/login/oauth/authorize?client_id=๋ณธ์ธ์clientid&์ ํ์ฌํญ&redirect_uri=๋ณธ์ธ์redircet์ฃผ์
<LoginBtn.jsx>
import React from 'react';
import styled from 'styled-components';
const LoginBtn = () => {
const loginUri = `https://github.com/login/oauth/authorize?client_id=๋ณธ์ธ์cliendid&scope=repo:status read:repo_hook user:email&redirect_uri=http://localhost:3000/callback`;
return (
<>
<GithubBtn href={loginUri}></GithubBtn>
</>
);
};
const GithubBtn = styled.a`
//์๋ต
`;
export default LoginBtn;
๋ก๊ทธ์ธ๋ฒํผ์ a link๋ฅผ ๊ฑธ์ด ๋ฒํผ ํด๋ฆญ์ ํด๋น loginUri๋ก ์ฐ๋๋๋๋กํ๋ค.
์ฟผ๋ฆฌ์คํธ๋ง์ผ๋ก ๋ฐ๊ธ๋ฐ์ clientid , ์ง์ ํ๋ redirect ์ฃผ์ , ๊ทธ์ธ ๋ก๊ทธ์ธ ์ ๋ ํฌ๊ด๋ จํ์ฌ ๋ฌผ์ด๋ณผ๊ฑด์ง๋ฑ์ ์ต์ ์ ๋ฃ์ด ์์ฒญํ๋ฉด code๋ฅผ url๋ก ์ ๋ฌ๋ฐ์ ์ ์๋ค .
<App.jsx>
function App() {
return (
<Router>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/callback" component={Callback} />
</Switch>
</Router>
);
}
App.jsx ์ ๋ก๊ทธ์ธ์ ์ฒ๋ฆฌํ component์ path ํด๋๊ณ
<Callback.jsx>
import { useEffect } from 'react';
import qs from 'qs';
import Loader from './Loader';
const Callback = ({ history, location }) => {
const authUri = `BE์ํ์ํ ์ฃผ์`;
useEffect(() => {
const getToken = async () => {
const { code } = qs.parse(location.search, {
ignoreQueryPrefix: true,
});
try {
const response = await fetch(`${authUri}?code=${code}`);
const data = await response.json();
localStorage.setItem('token', data.jwt);
localStorage.setItem('ProfileURL', data.avatar_url);
history.push('/');
} catch (error) {}
};
getToken();
}, [location, history, authUri]);
return <Loader />;
};
export default Callback;
Callback ์ปดํฌ๋ํธ์์ ์์ฒญํ ๊ฒ๋ค์ ์ฒ๋ฆฌํ๋ค .
์์ฒญ ํ qs ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํตํด code๋ฅผ ํ์ฑํด์ ์ป์ด๋ธ ํ -> ์ฟผ๋ฆฌ์คํธ๋ง์ผ๋ก GET์์ฒญ์ ๋ณด๋ธ๋ค .
๋ก๊ทธ์ธ ์๋ฃ ํ์๋ history pushํ์ฌ ๋ค์ Homeํ๋ฉด์ผ๋ก ์ด๋ํ๊ฒ๋ ์ค์
4)access-token ๋ฐ๊ธ๋ฐ๊ธฐ 5)jwt ํ ๊ทผ ๋ฐ๊ธ๋ฐ์ ์ฌ์ฉ
BE ๋จ์์ access-token์๋ฐ๊ธ๊ณผ์ ๋ณด ์์ฒญ์ ์ฒ๋ฆฌํ์ฌ ์ ๋ฌํด์ค์ผ๋ก
response๋ก ๋ฐ์์ ์ํ๋ data๋ localStorage์ ๋ด์์ ์ฌ์ฉํ๋ค.
์งํ ๋น์ ๋ฏธ๋ฆฌ BE์ ํ์ํด์ ๊นํ๋ธ ํ๋กํ ์ด๋ฏธ์ง url๋ ์์ฒญํด๋จ์ด์,
jwt์ ํจ๊ป ์ด๋ฏธ์งurl์ ์ ๋ฌ๋ฐ์๋ค .
๊ทธ ํ ๋ง์๊ป ์ฌ์ฉ!!!!!!!!
import React, { useState, useEffect } from 'react';
import styled from 'styled-components';
import LoginBtn from './LoginPage';
const AccountModal = ({ setProfileURL }) => {
const [isLogin, setIsLogin] = useState(false);
const token = localStorage.getItem('token');
useEffect(() => {
if (token) {
setIsLogin(true);
}
}, [token]);
const handleLogOut = () => {
setIsLogin(false);
setProfileURL(null);
localStorage.removeItem('token');
localStorage.removeItem('ProfileURL');
};
return (
<AccountModalDiv>
{isLogin ? (
<AccountLogout onClick={() => handleLogOut()}>๋ก๊ทธ์์</AccountLogout>
) : (
<AccountModalItem>
<LoginBtn />
</AccountModalItem>
)}
</AccountModalDiv>
);
};
export default AccountModal;
localStorage์ token์กด์ฌ ์ ๋ฌด์ ๋ฐ๋ผ ๋ก๊ทธ์ธ๊ณผ ๋ก๊ทธ์์์ด ๊ฐ๋ฅํ๊ฒ ๋ง๋ค์๊ณ ,
๋ก๊ทธ์ธ ํ์ ์ฌ์ฉ์์ด๋ฏธ์ง๊ฐ ๊นํ๋ธ ์ด๋ฏธ์ง๋ก ๋ฐ๋๋ ๊ท์ฌ์ด ๊ธฐ๋ฅ๋ ๊ตฌํํ๋ค!!
FE๋จ์์ POST ํ๋ ๋ฐฉ๋ฒ์ ํ๋ธ๋ก๊ทธ์ ๋ง์ ,
BE์ ํ์ ์ ํ์ฉ ๊ฐ๋ฅํ ๊ฐ๋จํ ๋ฐฉ๋ฒ์ผ๋ก ์ฒ๋ฆฌํด ๋ณด์์ต๋๋ค!
์ฐธ๊ณ (https://devhyun.com/blog/post/15)
๋๊ธ