-
Notifications
You must be signed in to change notification settings - Fork 6
Feat: 구글 간편 로그인 기능 구현 #80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b37918d
ce01544
6486d14
f5f67bc
78d9d73
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| import axios from "axios"; | ||
| import axiosInstance from "@/lib/api/axiosInstanceApi"; | ||
| import { NextApiRequest, NextApiResponse } from "next"; | ||
| import { serialize } from "cookie"; | ||
| import { jwtDecode } from "jwt-decode"; | ||
|
|
||
| interface GoogleUserInfo { | ||
| name: string; | ||
| } | ||
|
|
||
| const handler = async (req: NextApiRequest, res: NextApiResponse) => { | ||
| try { | ||
| const { code } = req.query; | ||
| if (!code) { | ||
| return res.status(400).json({ message: "인증 코드가 없습니다." }); | ||
| } | ||
|
|
||
| const clientId = process.env.GOOGLE_CLIENT_ID; | ||
| const clientSecret = process.env.GOOGLE_CLIENT_SECRET; | ||
| const redirectUri = | ||
| process.env.GOOGLE_REDIRECT_URI || "http://localhost:3000/"; | ||
|
|
||
| if (!clientId || !clientSecret) { | ||
| return res | ||
| .status(500) | ||
| .json({ message: "Google API 클라이언트 정보가 설정되지 않았습니다." }); | ||
| } | ||
|
|
||
| // 토큰 요청 | ||
| const tokenUrl = "https://oauth2.googleapis.com/token"; | ||
| const params = { | ||
| code: code as string, | ||
| client_id: clientId, | ||
| client_secret: clientSecret, | ||
| redirect_uri: redirectUri, | ||
| grant_type: "authorization_code", | ||
| }; | ||
|
|
||
| const tokenResponse = await axios.post(tokenUrl, params); | ||
| const { id_token } = tokenResponse.data; | ||
| if (!id_token) { | ||
| return res | ||
| .status(401) | ||
| .json({ message: "ID 토큰을 가져오지 못했습니다." }); | ||
| } | ||
|
|
||
| // Google ID 토큰에서 사용자 정보 추출 | ||
| const userInfo: GoogleUserInfo = jwtDecode(id_token); | ||
| const { name } = userInfo; | ||
| console.log(name); | ||
|
|
||
| // 이미 회원인지 체크 | ||
| try { | ||
| const loginResponse = await axiosInstance.post("/auth/sign-in/google", { | ||
| token: id_token, | ||
| redirectUri, | ||
| }); | ||
|
|
||
| const accessToken = loginResponse.data.access_token; | ||
| if (accessToken) { | ||
| res.setHeader( | ||
| "Set-Cookie", | ||
| serialize("accessToken", accessToken, { | ||
| httpOnly: true, | ||
| secure: process.env.NODE_ENV === "production", | ||
| sameSite: "lax", | ||
| maxAge: 60 * 60 * 24, | ||
| path: "/", | ||
| }) | ||
| ); | ||
| return res.redirect("http://localhost:3000"); | ||
| } | ||
| } catch (loginError: any) { | ||
| console.error( | ||
| "로그인 실패:", | ||
| loginError.response?.data || loginError.message | ||
| ); | ||
|
|
||
| // 로그인 실패 시 회원가입 시도 | ||
| try { | ||
| const signUpResponse = await axiosInstance.post( | ||
| "/auth/sign-up/google", | ||
| { | ||
| name: name || "사용자", | ||
| token: id_token, | ||
| redirectUri: "http://localhost:3000", | ||
| } | ||
| ); | ||
|
|
||
| const accessToken = signUpResponse.data.access_token; | ||
| if (accessToken) { | ||
| res.setHeader( | ||
| "Set-Cookie", | ||
| serialize("accessToken", accessToken, { | ||
| httpOnly: true, | ||
| secure: process.env.NODE_ENV === "production", | ||
| sameSite: "lax", | ||
| maxAge: 60 * 60 * 24, | ||
| path: "/", | ||
| }) | ||
| ); | ||
| return res.redirect("http://localhost:3000"); | ||
| } | ||
| } catch (signUpError: any) { | ||
| console.error( | ||
| "회원가입 실패:", | ||
| signUpError.response?.data || signUpError.message | ||
| ); | ||
| return res.status(500).json({ | ||
| message: "회원가입 중 오류가 발생했습니다.", | ||
| error: signUpError.response?.data || signUpError.message, | ||
| }); | ||
| } | ||
| } | ||
| } catch (error: any) { | ||
| console.error("Error:", error.response?.data || error.message); | ||
| return res.status(500).json({ | ||
| message: "서버 오류", | ||
| error: error.response?.data || error.message, | ||
| }); | ||
| } | ||
| }; | ||
|
|
||
| export default handler; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,21 +1,55 @@ | ||
| import { proxy } from "@/lib/api/axiosInstanceApi"; | ||
| import axios from "axios"; | ||
| import { useEffect } from "react"; | ||
|
|
||
| const Google = () => { | ||
| useEffect(() => { | ||
| const hash = window.location.hash; | ||
| const params = new URLSearchParams(hash.substring(1)); | ||
| const token = params.get("access_token"); | ||
| console.log(token); | ||
| const idToken = params.get("id_token"); // Google에서 전달받은 id_token | ||
| const accessToken = params.get("access_token"); // Google에서 전달받은 id_token | ||
|
|
||
| axios | ||
| .get(`https://www.googleapis.com/oauth2/v2/userinfo`, { | ||
| headers: { Authorization: `Bearer ${token}` }, | ||
| }) | ||
| .then((res) => console.log(res)); | ||
| if (accessToken) { | ||
| console.log(" Access Token:", accessToken); | ||
| proxy | ||
| .post("/api/auth/sign-up/google", { | ||
| name: "박문균", | ||
| token: accessToken, | ||
| redirectUri: "http://localhost:3000/google", | ||
| }) | ||
|
Comment on lines
+15
to
+19
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 테스트 하기 위해 name 을 고정으로 넣어보신 건가욧!?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아 이 페이지는 없애야하는 데 깜빡했네여 merge하기 전에 수정해서 push할게욥 |
||
| .then((response) => { | ||
| console.log("Authentication Success:", response.data); | ||
| // 성공적인 로그인 처리 후, 리다이렉션 등의 작업을 할 수 있습니다. | ||
| }) | ||
| .catch((error) => { | ||
| console.error("Authentication Error:", error); | ||
| }); | ||
| } else { | ||
| console.error("Access Token이 없습니다."); | ||
| } | ||
|
|
||
| if (idToken) { | ||
| console.log("Id Token:", idToken); | ||
|
|
||
| // 서버로 id_token을 전달하여 인증을 요청합니다. | ||
| proxy | ||
| .post("/api/auth/sign-in/google", { | ||
| token: idToken, | ||
| redirectUri: "http://localhost:3000/google", | ||
| }) | ||
| .then((response) => { | ||
| console.log("Authentication Success:", response.data); | ||
| // 성공적인 로그인 처리 후, 리다이렉션 등의 작업을 할 수 있습니다. | ||
| }) | ||
| .catch((error) => { | ||
| console.error("Authentication Error:", error); | ||
| }); | ||
| } else { | ||
| console.error("Id Token이 없습니다."); | ||
| } | ||
| }, []); | ||
|
|
||
| return <div>안녕</div>; | ||
| return <div>Google OAuth 로그인 완료</div>; | ||
| }; | ||
|
|
||
| export default Google; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GOOGLE_CLIENT_ID는 .env 파일에서 관리하는거죠? 한번 공유 주시면 좋겠습니다 : )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아이디 생성 과정에 대해서 말씀하시는거죠?? 팀 미팅때 공유해드리겠습니당~