Jieunny์ ๋ธ๋ก๊ทธ
S3) Unit 7. [์ค์ต] OAuth(๊นํ๋ธ) ์ฌ์ฉํด์ ๋ก๊ทธ์ธ ๊ธฐ๋ฅ ๊ตฌํํ๊ธฐ ๋ณธ๋ฌธ
S3) Unit 7. [์ค์ต] OAuth(๊นํ๋ธ) ์ฌ์ฉํด์ ๋ก๊ทธ์ธ ๊ธฐ๋ฅ ๊ตฌํํ๊ธฐ
Jieunny 2023. 3. 9. 14:28๐ฃ ๊นํ๋ธ ๋ก๊ทธ์ธ ์ธ์ฆ ์ฌ์ฉํด์ ๋ก๊ทธ์ธ ๊ธฐ๋ฅ ๊ตฌํํ๊ธฐ
- client๋ง ๊ตฌํ
๐ญ. client ํ์ผ ๊ตฌ์กฐ
src
ใด pages
ใด components
ใด Loading.js : ๋ก๋ฉ ํ๋ฉด ์ปดํฌ๋ํธ
ใด UserInfo.js : ๋ก๊ทธ์ธ ์ฑ๊ณต ํ๋ฉด ๋ํ๋๋ ์ ์ ์ ๋ณด ์ปดํฌ๋ํธ
ใด Login.js : Authorization code ๋ฐ์์ค๊ธฐ
- Github์ ์์ฒญ์ ๋ณด๋ด์ Authorization code๋ฅผ ๋ฐ์์จ๋ค.
ใด MyPage.js : ๋ก์ปฌ ์๋ฒ๋ฅผ ํตํด Github ๋ฆฌ์์ค ์๋ฒ์ ์ ์ ์ ๋ณด ์์ฒญ, ๋ก๊ทธ์์
- Authorization code๋ฅผ ๋ฐ์์๋ค๋ฉด App.js์ getAccessToken ํจ์๊ฐ ์คํ๋๋ค.
- ์ด ํจ์๋ฅผ ํตํด ์๋ฒ์ /callback ์๋ํฌ์ธํธ๋ก ์์ฒญ์ ๋ณด๋ด๊ณ , ์๋ต์ผ๋ก ๋ฐ์์จ Access Token์ App ์ปดํฌ๋ํธ์ state๋ก ์ ์ฅํ๊ณ , MyPage ์ปดํฌ๋ํธ์์ props ๋ฐ์์ ์ฌ์ฉํ๋ค.
- ๋ฐ์์จ Access Token์ ์ด์ฉํด์ /userInfo๋ก ์์ฒญํ๋ฉด serverResource์ Github Resource ์๋ฒ์ ์์ฒญํ ๋ฆฌ์์ค์ธ githubUserData๊ฐ ์๋ต์ผ๋ก ์ ๋ฌ๋๋ค.
- ๊นํ๋ธ ์ ์ ์ ๋ณด์ ๋ก์ปฌ ์๋ฒ์ ์๋ ์ ๋ณด๊ฐ ๋ง์ดํ์ด์ง ํ๋ฉด์ ๋ด๊ฒจ์ผ ํ๋ค.
- ๋ก๊ทธ์์ ๊ตฌํ : ๋ก์ปฌ ์๋ฒ์ /logout์ ์ก์ธ์ค ํ ํฐ์ ์ด์ฉํด ์์ฒญ์ ๋ณด๋ด์ ์ ์ ์ ํ ํฐ์ ์ง์ฐ๊ณ , ์ํ๋ฅผ ์ ๋ฐ์ดํธ ํ๋ค.
ใด App.js : Access Token ๋ฐ์์ค๊ธฐ
์๋ฒ์ .env : CLIENT_ID์ CLIENT_SECRET ์ค์
โ๏ธ ๊นํ๋ธ์ ๋ด๊ฐ ๊ตฌํํ OAuth ์ฑ์ ๋ฑ๋กํ๋ ๊ณผ์ ์ด ๋จผ์ ์คํ๋์ด์ผ ํ๋ค.
โฐ Homepage URL ๋ฐ Authorization callback URL์ ํด๋น ๊ณผ์ ์ ํด๋ผ์ด์ธํธ ์ฃผ์(http://localhost:3000)๋ก ๋ฆฌ๋๋ ์ ํ๋ค.
โฐ ์ด ๊ณผ์ ์ ํตํด CLIENT_ID์ CLIENT_SECRET์ ๋ฐ๊ธ๋ฐ์ ์ ์๋ค.
๐ฎ. ์ฝ๋ ๊ตฌํ
๐ Login.js
export default function Login() {
const CLIENT_ID = '๋ด CLIENT_ID';
// ๋ฐ์์จ ํด๋ผ์ด์ธํธ ID๋ฅผ ๊ฐ์ ธ์์ github ํ์ด์ง๋ก ๋ค์ด๊ฐ๊ฒ ํด์ค๋ค.
const loginRequestHandler = () => {
// 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
return window.location.assign(
`https://github.com/login/oauth/authorize?client_id=${CLIENT_ID}`
);
};
}
โฐ CLIENT_ID ๊ฐ์ ธ์ฌ ๋ process.env.CLIENT_ID๋ก ํ๋๋ฐ undefined๊ฐ ๋์์ ๊ทธ๋ฅ ํ๋์ฝ๋ฉ์ผ๋ก ๋ฃ์ด์คฌ๋ค.. ์ด๋ ๊ฒ ํ๋ฉด ์๋๋ ๊ฒ ๊ฐ๊ธดํ๋ฐ ์ด๋ฐ ์ค์๊ฐ ์๊ฐ์ ์ค๋ช
ํด์ฃผ์๊ฒ ์ง.. -> ๊ทธ๋ฅ ๋ฃ์ด๋ ์๊ด ์๋ค๊ณ ํจ
โฐ ์ process.env.CLIENT_ID๊ฐ ์๋๋? -> ํ๊ฒฝ ๋ณ์๋ฅผ ์ ๋๋ก ๊ฐ์ ธ์ค์ง ๋ชปํด์ -> ๋ฆฌ์กํธ์์ ํ๊ฒฝ ๋ณ์๋ฅผ ์ฐ๋ ค๋ฉด .env ํ์ผ ์ค์ ํ ๋ REACT_APP_CLIENT_ID ๋ก ์จ์ผํจ(๋ณ์ ์์ REACT_APP_ ์ถ๊ฐํด์ค์ผํ๋ค!!)
๐ App.js
function App() {
const [isLogin, setIsLogin] = useState(false);
const [accessToken, setAccessToken] = useState('');
const getAccessToken = async (authorizationCode) => {
// ๋ฐ์์จ Authorization Code๋ก ๋ค์ OAuth App์ ์์ฒญํด์ Access Token์ ๋ฐ์ ์ ์์ต๋๋ค.
// Access Token์ ๋ณด์ ์ ์ง๊ฐ ํ์ํ๊ธฐ ๋๋ฌธ์ ํด๋ผ์ด์ธํธ์์ ์ง์ OAuth App์ ์์ฒญ์ ํ๋ ๋ฐฉ๋ฒ์ ๋ณด์์ ์ทจ์ฝํ ์ ์์ต๋๋ค.
// Authorization Code๋ฅผ ์๋ฒ๋ก ๋ณด๋ด์ฃผ๊ณ ์๋ฒ์์ Access Token ์์ฒญ์ ํ๋ ๊ฒ์ด ์ ์ ํฉ๋๋ค.
// TODO: ์๋ฒ์ /callback ์๋ํฌ์ธํธ๋ก Authorization Code๋ฅผ ๋ณด๋ด์ฃผ๊ณ Access Token์ ๋ฐ์์ต๋๋ค.
// Access Token์ ๋ฐ์์จ ํ state์ Access Token์ ์ ์ฅํ์ธ์
const res = await axios.post("http://localhost:4000/callback", {
// /callback์ผ๋ก authorizationCode๋ฅผ ๋ณด๋ด์ฃผ๊ณ , ์๋ต์ผ๋ก Access Token์ ๋ฐ์์จ๋ค.
authorizationCode: authorizationCode,
});
setAccessToken(res.data.accessToken);
// ๋ฐ์์จ ์ก์ธ์ค ํ ํฐ์ state์ ๋ฃ์ด์ฃผ๊ณ
setIsLogin(true);
// ๋ก๊ทธ์ธ์ด ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋์์ผ๋ ์ํ๋ ๋ฐ๊ฟ์ค๋ค.
};
useEffect(() => {
// Authorization Server๋ก๋ถํฐ ํด๋ผ์ด์ธํธ๋ก ๋ฆฌ๋๋ ์
๋ ๊ฒฝ์ฐ, Authorization Code๊ฐ ํจ๊ป ์ ๋ฌ๋ฉ๋๋ค.
// ex) http://localhost:3000/mypage?code=5e52fb85d6a1ed46a51f
const url = new URL(window.location.href);
const authorizationCode = url.searchParams.get('code');
if (authorizationCode) {
getAccessToken(authorizationCode);
}
}, []);
}
๐ Mypage.js
export default function Mypage({accessToken, setIsLogin, setAccessToken}) {
const [githubUser, setGithubUser] = useState(null);
const [serverResource, setServerResource] = useState(null);
const [isLoading, setIsLoading] = useState(true);
const logoutHandler = () => {
// TODO: /logout์ ํตํด ์ฌ์ฉ์๊ฐ ๋ก๊ทธ์์๋๋๋ก ๊ตฌํํ์ธ์.
// prop์ผ๋ก ๋ฐ์ Access Token์ ์ด์ฉํด /logout ์๋ํฌ์ธํธ๋ก ์์ฒญ์ ๋ณด๋ด์ผํฉ๋๋ค.
// ์์ฒญ์ด ์ฑ๊ณตํ๋ค๋ฉด isLogin ์ํ๋ฅผ false๋ก ์
๋ฐ์ดํธํด์ผ ํฉ๋๋ค.
axios
.delete("http://localhost:4000/logout", { data: {accessToken} })
// ๋ก๊ทธ์์์ ์๋ฒ์์ delete ๋ฉ์๋๋ก ๋ฐ๊ณ ์์ผ๋ฏ๋ก delete๋ก ์์ฒญ์ ๋ณด๋ธ๋ค.
.then((res) => {
setIsLogin(false);
setAccessToken("");
setGithubUser(null);
setServerResource(null);
// ๋ก๊ทธ์์์ด ์ฑ๊ณตํ์ผ๋ฏ๋ก ๋ก๊ทธ์ธ ์ํ๋ฅผ ๋ฐ๊ฟ์ฃผ๊ณ , ๋ชจ๋ ์ด๊ธฐํ ์์ผ์ค๋ค.
})
.catch((err) => console.log(err));
};
useEffect(() => {
// TODO: /userinfo๋ฅผ ํตํด ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๋ฐ์์ค์ธ์.
// prop์ผ๋ก ๋ฐ์ Access Token์ ์ด์ฉํด /userinfo ์๋ํฌ์ธํธ๋ก ์์ฒญ์ ๋ณด๋ด์ผํฉ๋๋ค.
// ์๋ต์ผ๋ก ๋ฐ์ ๋ฐ์ดํฐ๋ฅผ githubUser, serverResource์ ์ํ๋ก ์
๋ฐ์ดํธํด์ผํฉ๋๋ค.
// isLoading ์ํ๋ฅผ false๋ก ์
๋ฐ์ดํธํด์ผ ํฉ๋๋ค.
axios
.post("http://localhost:4000/userInfo", { accessToken })
// ์ ์ ์ ๋ณด๋ฅผ ๋ฐ์์ค๊ธฐ ์ํด์ userInfo๋ก ์์ฒญ์ ๋ณด๋ธ๋ค.
.then((res) => {
// ์ฑ๊ณต์ ์ผ๋ก ์ ์ ์ ๋ณด๋ฅผ ๋ฐ์์ค๋ฉด
const { githubUserData, serverResource } = res.data;
// ๋ฐ์์จ ๋ฐ์ดํฐ์์ ํ์ํ ์ ๋ณด๋ง ๋ฝ์์ ์ ์ฅํ๋ค.
setGithubUser(githubUserData);
// state์ ๊ฐ๊ฐ ์ ์ฅํด์ฃผ๊ณ
setServerResource(serverResource);
setIsLoading(false);
// ๋ก๋ฉ์ ๋๋ด๊ณ ์ ์ ์ ๋ณด๋ฅผ ํ๋ฉด์ ๋์์ค๋ค.
})
.catch((err) => console.log(err));
}, []);
}
๐ฏ. ์์ฐํ๋ฉด
'CodeStates > Training' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
S4) Unit 1. [์ค์ต] Stack & Queue ๋ฌธ์ (0) | 2023.03.14 |
---|---|
S3) Unit 8. [์ค์ต] Coz'Mini Hackaton (Todo-List) (2) | 2023.03.10 |
S3) Unit 7. [์ค์ต] Token & Cookie ์ฌ์ฉํด์ ๋ก๊ทธ์ธ ๊ธฐ๋ฅ ๊ตฌํํ๊ธฐ (0) | 2023.03.09 |
S3) Unit 7. [์ค์ต] Cookie๋ก ๋ก๊ทธ์ธ ๊ธฐ๋ฅ ๊ตฌํํ๊ธฐ (0) | 2023.03.07 |
S3) Unit 4. [์ค์ต] CMarket Redux (0) | 2023.02.27 |