๊ตฌ๊ธ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ๊ฐ์ ์ฌ์ดํธ sns ๋ก๊ทธ์ธ์ ๊ตฌํํ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ์ผ๋จ ํ๋ฆ๋๋ ์นด์นด์ค ๊ตฌํ๊ณผ ๊ฐ๋ค.
๊ณ์ ์ด ์กด์ฌํ์ง ์์ผ๋ฉด ์ฌ์ฉ์ ์ ๋ณด๊ฐ ์๋ค๋ ๋ฉ์์ง๋ฅผ ๋์ ๊ด๋ฆฌ์๊ฐ ๋ฐ๋ก ๋ฑ๋กํด์ผ๋ง ํ๋ ํ๋ฆ์ด๋ค.
(https://moon-lilac.tistory.com/183)
Next.js | ์นด์นด์ค ๋ก๊ทธ์ธ ๊ตฌํํ๊ธฐ
๊ธฐ์กด์ ํ์ด์ง์ ์์ ๋ก๊ทธ์ธ ๊ธฐ๋ฅ์ ์ถ๊ฐํ๋ ค๊ณ ํ๋ค.๊ทธ๋์ ์ด๋ฏธ ์๋ ์ฌ์ฉ์์ ์๋ก ๋ก๊ทธ์ธํ ์ฌ์ฉ์์์ ๋งค์นญ๊ธฐ๋ฅ์ด ํ์ํ๋ค.๊ทธ๋ฆฌ๊ณ ํ์๊ฐ์ ์ด ํ์ํ ์ฌ์ดํธ๊ฐ ์๋๋ผ, ๊ด๋ฆฌ์๊ฐ ์ฌ์ฉ์
moon-lilac.tistory.com
+ ์ถ๊ฐ์ฌํญ ๐ก
๊ธฐ์กด์์ ์ถ๊ฐ๋๊ฒ ์๋ค๋ฉด ์ฌ์ฉ์ ์ ๋ณด(์ด๋ฆ, ์ ํ๋ฒํธ)๋ฅผ ์ ๋ ฅํ๋ ํ์ด์ง๋ฅผ ๋์ฐ๊ธฐ ์ ์
์ธ๊ฐ์ฝ๋์ sns ์ฝ๋๋ง ๋ณด๋ด๋ api๋ฅผ ๋ฐ๋ก ํ์ ๊ธฐ์กด์ ๋ก๊ทธ์ธํ๋ ์ ์ (snsid๊ฐ ์กด์ฌ)์ด ์์ผ๋ฉด,
๋ฐ๋ก ๋ก๊ทธ์ธ์ ์์ผ์ฃผ๊ณ , ์์ผ๋ฉด ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ ๋ ฅํ๋ ํ์ด์ง๋ฅผ ๋์์ฃผ์ด ๊ฑฐ๊ธฐ์ ํ ํฐ์ ๋ฐ์์ ์ฒ๋ฆฌํ๋ ํ์์ด๋ค.
์ด๊ฑด ์ด๋ ค์ด ๋ถ๋ถ์ด ์๋์ด์, ๋ง๋ก ์ค์ค ์ ์ด๋ณด์๋ฉด,,,
sns id๋ฅผ ํ์ธํ๋ api๋ฅผ ํ์ธ ๋ loading ์ฒ๋ฆฌ๋ฅผ ํด์ฃผ์ด ๋ก๋ฉํ๋ฉด์ ๋ณด์ฌ์ฃผ๊ณ
sns id๊ฐ ์์ ๊ฒฝ์ฐ ํ ํฐ๋ ํจ๊ป ๋ฐ์์ ํค๋์ ๋ฃ์ด์ฃผ๊ณ ๋ฐ๋ก ๋ก๊ทธ์ธ์ํค๊ณ , ์์ ๊ฒฝ์ฐ์ redirectํ๋ฉด์ ๋ณด์ฌ์ฃผ์ด
loginMutate๋ฅผ ๋ฒํผ ํด๋ฆญ์ ํ์์ฃผ๋ฉด ๋๋ค.
์ผ๋จ ๋ค์๋ก ์์!

1. ๋ค์ด๋ฒ ๊ฐ๋ฐ์์ผํฐ์์ ์ ํ๋ฆฌ์ผ์ด์ ์ถ๊ฐ
์ฌ๊ธฐ์ Client ID๋ฅผ ๊ฐ์ ธ์ค๊ณ ,
API์ค์ ์์ ๊ทธ๋์ ํด์๋ ๊ฒ๋ค์ ํด์ค๋ค..
Callback URL์ด Redirect Uri ์ธ๋ฏ..
(ํ๋ฉด์ ํ ์คํธํ๋๋ผ naver๊น์ง๋ง ์ ํ์์ง๋ง, naver/oauth ๊น์ง ์ ๋ ฅ๋์ด์ผํจ. oauth route๋ก ์ด๋ํ๊ธฐ ๋๋ฌธ์)
๊ทธ๋ฆฌ๊ณ ๋ค์ด๋ฒ๋ ํ ์คํธ ๊ณผ์ ์ผ ๋๋ ๋ฉค๋ฒ๊ด๋ฆฌ ํญ์์ ์์ด๋๋ฅผ ๋ฑ๋กํด์ฃผ์ด์ผ
ํด๋น์์ด๋๊ฐ ๋ก๊ทธ์ธ ํ ์คํธ์ ์ฐธ์ฌํ ์ ์๋ค.. ๊ทธ๋ฌ๋๊น ๋ฐฐํฌํด์ ์ฐ๋ ค๋ฉด ๋ค์ด๋ฒ์์ ๊ฒ์์์ฒญ์ ๋ฐ์์ผํจ!
์๋ฌดํผ ๋ค๋ฅธ ๋ค์ด๋ฒ ์์ด๋๋ก๋ ๋ก๊ทธ์ธํ ์์ ๋ฉค๋ฒ๊ด๋ฆฌ์์ ์์ด๋๋ฅผ ์ ๋ ฅํด์ค!
์ด์ ํ๊ฒฝ๋ณ์์ ํด๋น๋ด์ฉ์ ์ ์ด๋๋ค.
2. Next์ ๋ค์ด๋ฒ ๋ก๊ทธ์ธ ๊ฐ๋ฐ์ค์
next 13~14๋ layout.tsx ์, ๊ทธ ์ดํ๋ _document.tsx๋ด <script>์ sdk๋ฅผ ์ถ๊ฐํด์ค๋ค.
๐ญ next 13, 14
layout.tsx
declare global {
interface Window {
...
naver: any;
}
}
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html>
<body>
...
</body>
<Script
src="https://static.nid.naver.com/js/naveridlogin_js_sdk_2.0.2.js"
strategy="beforeInteractive"
/>
</html>
);
}
Script๋ถ๋ถ์ด๋ declare์ ์ธ์ ํด์ค๋ค.
๐จ next 12 ์ดํ
_app.tsx
function MyApp({ Component, pageProps }: AppProps) {
return ( ....
<Layout>
...
<Script
src="https://static.nid.naver.com/js/naveridlogin_js_sdk_2.0.2.js"
strategy="beforeInteractive"
/>
</Layout>
...
);
}
3. ๋ฐฑ์๋์ ์ธ๊ฐ ์ฝ๋๋ฅผ ๋ณด๋ผ ํ์ด์ง ๋ง๋ค๊ธฐ
๊ฐ์ next ๋ฒ์ ์ ๋ง๊ฒ "use client"๋ฅผ ์ ์ธํด์ค ๊ฑด ํด์ฃผ๊ณ ํ๋ฉด ๋จ
Login.tsx
function Login() {
...
const naverRef = useRef<any>();
const loginWithNaver = (snsType: string | null) => {
const naverLogin = new naver.LoginWithNaverId({
clientId: process.env.NEXT_PUBLIC_NAVER_CLIENT_ID,
callbackUrl: `${process.env.NEXT_PUBLIC_OAUTH_REDIRECT}/${snsType}/oauth`,
isPopup: false,
loginButton: { color: "green", type: 1, height: "30" },
callbackHandle: true,
});
naverLogin.init();
naverRef.current.children[0].click(); // ์ปค์คํ
ํ ์์ด์ฝ์ผ๋ก ๋๋ฌ์ฃผ๊ธฐ ์ํ useRef
};
...
<button onClick={() => loginWithNaver("naver")} type="button">
<NaverIcon />
</button>
<div id="naverIdLogin" style={{ display: "none" }} ref={naverRef} />
...
๋ค์ด๋ฒ๋ ๋ค๋ฅธ ๊ฒ๋ค๊ณผ ๋ค๋ฅด๊ฒ ๋ฒํผ์ ๋ฐ๋ก ์ ๊ณตํ๋ค.
๊ทธ๋์ id๊ฐ "naverIdLogin"์ธ ๋ฒํผ์ ์ฌ์ฉํด์ผํ๋๋ฐ, ์ด๊ฒ ๋์์ธ์ด ๋ค๋ฅธ ๊ฒ๋ค๊ณผ ์ผ์นํ์ง๊ฐ ์์์
๋ฐ๋ก ์ปค์คํ ์ ํด์ฃผ๋ ๊ณผ์ ์ด ํ์ํ๋ค (ํ์ผ์ ๋ค์ด๋ฒ์์ ๊ท๊ฒฉ์ ๋ง๊ฒ ๋ฐ์์์ผํจ ์๋ฌด๋ ๊ฒ๋ ์ปค์คํ ํ๋ฉด ์๋จ!)
์ปค์คํ ํ ํ์ผ์ <NaverIcon /> ๋ก ์ง์ ํ๊ณ ,
const NaverIcon = styled.div`
width: 183px;
height: 45px;
background: url("/images/naver_login.png") no-repeat;
background-size: cover;
box-shadow: -5px -5px 10px #fff, 5px 5px 8px #babebc;
`;
div ์ css backgroud cover๋ก ์ด์ฉํด์ฃผ์๋ค.
๋ฒํผ ๊ฐ์ด๋ฐ์ ์ด๋ฏธ์ง๋ฅผ ๋ฃ์๋๋ฐ <img> ํ๊ทธ๋ ์์ธ์ง ์๋ผ์ ใ ,ใ ์ด์ ๋ ๋ชจ๋ฆ
๊ทธ๋ฆฌ๊ณ ๋ค์ด๋ฒ์์ ์ง์ ํด์ค id๋ฅผ ๊ฐ์ง๊ณ ์๋ div๋ display:none ์ฒ๋ฆฌ๋ฅผ ํด์ฃผ๋ ๋์ ์
์ด ๋ฒํผ์ ํด๋ฆญํด์ผ๋ง ๋์ํ๊ธฐ ๋๋ฌธ์ ์ด div๋ฅผ ์ ํํด์ค ref๋ฅผ ์ง์ ํด์ฃผ์๋ค.
Oauth.tsx
์ด ํ์ด์ง์์ ๊ตฌ๊ธ, ์นด์นด์ค๋ ๊ฐ์ด ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์
์๋์ผ๋ก router.query๋ฅผ ์ด์ฉํด ?code="์ด ๋ถ๋ถ"์ ์๋ ์ฝ๋๋ฅผ ๊ฐ์ง๊ณ ์ค๋๋ฐ,
๋ค์ด๋ฒ๋ #access_token="์ด ๋ถ๋ถ"์ ์๋ฒ์ ์ ๋ฌํด์ฃผ์ด์ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์ค๋ ๋ฐฉ์์ด์๋ค.
๊ทธ๋์ ๋ค์ด๋ฒ๋ก ๋ก๊ทธ์ธํ์ ๊ฒฝ์ฐ (oauth์ด์ ์ [sns]๊ฐ ๋์ ๋ผ์ฐํธ์ด๋ฏ๋ก url ์ฟผ๋ฆฌ์์ naver ๊ธ์ด์ด)
http://localhost:3000/login/naver/oauth#access_token=ANDFELKFLK์ด์ฉ๊ณ ์ ์ฉ๊ณ ์ธ๊ฐ์ฝ๋&state=135135djlfjk31kdkf31k&token_type=bearer&expires_in=3600
์ด๋ฐ์์ผ๋ก ๊ตฌ์ฑ๋์ด์์ด access_token ๋ท ๋ถ๋ถ์ ๊ฐ์ ธ์ค๋ ค๋ฉด ์๋ ์์ ์ด์ฉํ๋ค
window.location.href.split("=")[1].split("&")[0]
์ฒ์์๋
const { code: authCode, sns: snsType } = router.query;
์ด๋ ๊ฒ๋ง ๋์ด์์๋๋ฐ, ์ด์ authCode๋ฅผ ๋ถ๊ธฐ์ฒ๋ฆฌ๋ฅผ ํด์ค์ผํ๋ค.
๊ทธ๋์ const๋ฅผ let์ผ๋ก ๋ฐ๊พธ๊ณ ,
if๋ฌธ์ผ๋ก
if (snsType === "naver") {
authCode = window.location.href.split("=")[1].split("&")[0];
} else {
authCode = router.query.code;
}
์ด๋ ๊ฒ ํด์ฃผ์๋๋ฐ ์๊ฐํด๋ณด๋ ์ด๋ฌ๋ฉด router.query.code๋ฅผ ๋๋ฒ์ด๋ ์ง์ ํด์ค์ ใ ใ ใ
๊ตณ์ด ์ด๋ ๊ฒ๊น์ง ํ ํ์ ์์ง ์ถ์ด์
let { code, sns: snsType }: any = router.query;
const authCode = snsType === "naver"
? window.location.href.split("=")[1].split("&")[0]
: code;
์กฐ~๊ธ ์์ ํด์คฌ๋ค ใ ใ ,,,
ํธ์ถํ๋ api๋ authCode๋ฅผ ๊ฐ์ง๊ณ ๋ณด๋ด๊ธฐ ๋๋ฌธ์ authCode์์ฒด๋ฅผ ๋ถ๊ธฐ์ฒ๋ฆฌํด์ฃผ์ด ํธ์ถ ์์์ ์์ ํด์ค ๊ฒ์ด ์์์
โ ?code="" ๋ก ๋ณด๋ด์ฃผ๊ธฐ
์๋ฒ๋จ์์ access_token์ผ๋ก ๋ง๊ณ ๊ธฐ์กด์ฒ๋ผ code๋ก ๋ณด๋ด๋ฌ๋ผ๊ณ ํด์ ๋ค๋ฅธ ๋ฐฉ์์ ์ด์ฉํ๋ค
Login.tsx
const loginWithNaver = (snsType: string | null) => {
window.location.href = `https://nid.naver.com/oauth2.0/authorize?
client_id=${process.env.NEXT_PUBLIC_NAVER_CLIENT_ID}&
redirect_uri=${process.env.NEXT_PUBLIC_OAUTH_REDIRECT}/${snsType}/oauth&
response_type=code
`;
}
...
<button onClick={() => loginWithNaver("naver")} type="button">
<NaverIcon />
</button>
...
//CSS ๋ ์๋ต
์ด๋ฐ์์ผ๋ก ์ ์ด์ค ํ ๋ฐ๋ก ๋ณด๋ด์คฌ๋ค.
๊ทธ๋ฌ๋๋ ๊ธฐ์กด์ฒ๋ผ login/naver/oauth?code="" ์ด๋ฐ์์ผ๋ก ๋์์ ์ธ๊ฐ์ฝ๋๋ฅผ ๋ณด๋ด์ฃผ๊ฒ๋จ.
๊ทผ๋ฐ ์ด๋ฐ ๋ฐฉ์์ script๋ฅผ layout ์ ์ ๋ ฅํ์ง ์์๋ ๋๋ค.... (?
๋ฐฉ์์ด ์ด๋ ๊ฒ ๋ค๋ฅธ ์ด์ ๊ฐ ๋ฌด์์ธ์ง ๊ถ๊ธํ๋ค @.@
ํน์ token์ ๋ฐ๋ก ๋ฐ๋ ๋ฐฉ์์ ์๋ฒ์ ๊ฐ์ ์์ด ๋ฐ๋ก ๋ก๊ทธ์ธ ๊ฐ๋ฅํ๊ฒ ํด์ฃผ๋ ๋ฐฉ์์ธ์ง,.,,

์ด์ ์ธ ๊ฐ์ง ๋ค ๊ตฌํ์๋ฃ!
์๋ฌ๊ฐ ์๊ธฐ๋ฉด ์ถ๊ฐ๋ก ์ฐจ์ฐจ ์ ์ด๋๊ฐ๊ฒ ์

'TIL > Next.js' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Next 14 | Chakra UI๋ฅผ next์์ ์ฌ์ฉํ๊ธฐ (0) | 2024.03.11 |
---|---|
Next.js | ๊ตฌ๊ธ ๋ก๊ทธ์ธ ๊ตฌํํ๊ธฐ (0) | 2024.03.05 |
Next.js | ์นด์นด์ค ๋ก๊ทธ์ธ ๊ตฌํํ๊ธฐ (1) | 2024.02.27 |
[TIL] Next.js 13 ๋ผ์ฐํ (4) | 2023.05.27 |
Next.js ๊ธฐ์ด 2 - component, props, state (0) | 2023.05.20 |