Backend
home
🕒

2024. 9. 20 (oAuth 실습)

생성일
2025/01/24 05:52
태그
소셜 로그인 구현 프로젝트 - 기존 미니 이커머스 프로젝트 파일에서 진행

SpringBoot

oAuth 계정 생성
// oAuth 계정 생성 private User generateOAuthUser(String accessToken, String provider) { // 설정 가져오기 OAuth2Properties.Client client = oAuth2Properties.getClients().get(provider); HttpHeaders headers = new HttpHeaders(); headers.add("Authorization", "Bearer " + accessToken); RestTemplate rt = new RestTemplate(); // 구글에 저장된 정보 ResponseEntity<JsonNode> responseEntity = rt.exchange(client.getUserInfoRequestUri(), HttpMethod.GET, new HttpEntity<>(headers), JsonNode.class); // response 상태에 따라 구분 if (!responseEntity.getStatusCode().is2xxSuccessful() || responseEntity.getBody() == null) { throw new ResponseStatusException(HttpStatus.NOT_FOUND, "사용자 정보를 가져올 수 없음"); } JsonNode jsonNode = responseEntity.getBody(); System.out.println(jsonNode); String email = null; String name = null; User user = null; try { if (jsonNode.has("response")) { // 네이버 email = jsonNode.get("response").get("email").asText(); name = jsonNode.get("response").get("name").asText(); } else if (jsonNode.has("email") && jsonNode.has("name")) { // 구글, Github email = jsonNode.get("email").asText(); name = jsonNode.get("name").asText(); } else if (jsonNode.has("id") && jsonNode.has("properties")) { // 카카오 email = jsonNode.get("id").asText() + "@kakao.com"; name = jsonNode.get("properties").get("nickname").asText(); } user = User.builder() .email(email) .name(name) .build(); } catch (RuntimeException e) { throw new RuntimeException("해당 사용자를 찾을 수 없습니다."); } return user; }
Java
복사

React

OAuthLogin.jsx
import { useParams } from "react-router-dom"; import { oauthAPI } from "../services/oauth"; import { setCookie } from "../utils/cookieUtil"; import { useEffect } from "react"; const OAuthLogin = () => { const { provider } = useParams(); const code = new URLSearchParams(window.location.search).get("code"); console.log("서버에 전달해야 하는 코드 값 : ", code); const oAuthAPI = { "kakao": (code) => oauthAPI.kakaoLogin(code), "google": (code) => oauthAPI.googleLogin(code), "github": (code) => oauthAPI.githubLogin(code), "naver": (code) => oauthAPI.naverLogin(code), } const login = async () => { try { console.log(provider); const response = await oAuthAPI[provider](code); if (response.status !== 200) { throw new Error("로그인 실패"); } else { setCookie("accessToken", response.data.accessToken, { path: "/" }); window.location.href = "/"; } } catch (error) { console.error(error); } } useEffect(() => { login(); }, [code]); return ( <div>로그인 처리 중 ~</div> ); } export default OAuthLogin;
JavaScript
복사
oauthAPI.js
import api from "./api"; export const oauthAPI = { googleLogin: (code) => api.get(`/oauth/google?code=${code}`), kakaoLogin: (code) => api.get(`/oauth/kakao?code=${code}`), githubLogin: (code) => api.get(`/oauth/github?code=${code}`), naverLogin: (code) => api.get(`/oauth/naver?code=${code}`) }
JavaScript
복사
LoginPage.jsx
import { useForm } from 'react-hook-form'; import { TextField, Button, Container, Typography, Box } from '@mui/material'; import { userAPI } from '../services/user'; import { useCookies } from 'react-cookie'; import { useNavigate } from 'react-router-dom'; import google from '../assets/google.png'; import kakao from '../assets/kakao.png'; import github from '../assets/github.png'; import naver from '../assets/naver.png'; const LoginPage = () => { const { register, handleSubmit, formState: { errors }, setError } = useForm(); const [, setCookie] = useCookies(['accessToken']); const navigate = useNavigate(); const onSubmit = async (data) => { try { const response = await userAPI.login(data); setCookie('accessToken', response.data.accessToken, { path: '/' }); navigate('/products'); } catch (error) { if (error.status === 401) { setError("email", { type: "manual", message: "로그인 실패! 아이디를 확인해주세요" }); setError("password", { type: "manual", message: "로그인 실패! 비밀번호를 확인해주세요" }); } } }; // 구글 로그인 핸들러 const handleGoogleLogin = () => { // 구글 로그인 버튼 클릭 시 이동 const params = new URLSearchParams({ scope: "email profile", response_type: "code", redirect_uri: process.env.REACT_APP_GOOGLE_REDIRECT_URI, client_id: process.env.REACT_APP_GOOGLE_ID, }); const GOOGLE_URL = `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`; // 지정한 경로로 이동 window.location.href = GOOGLE_URL; } // 카카오 로그인 핸들러 const handleKakaoLogin = () => { // 구글 로그인 버튼 클릭 시 이동하는 경로 지정 const params = new URLSearchParams({ response_type: "code", redirect_uri: process.env.REACT_APP_KAKAO_REDIRECT_URI, client_id: process.env.REACT_APP_KAKAO_ID, }) const KAKAO_URL = `https://kauth.kakao.com/oauth/authorize?${params.toString()}`; // 지정한 경로롤 이동 window.location.href = KAKAO_URL; } // 깃허브 로그인 핸들러 const handleGithubLogin = () => { const params = new URLSearchParams({ redirect_uri: process.env.REACT_APP_GITHUB_REDIRECT_URI, client_id: process.env.REACT_APP_GITHUB_ID, }); const GITHUB_URL = `https://github.com/login/oauth/authorize?${params.toString()}` // 지정한 경로로 이동 window.location.href = GITHUB_URL; } // 네이버 로그인 핸들러 const handleNaverLogin = () => { const params = new URLSearchParams({ response_type: "code", redirect_uri: process.env.REACT_APP_NAVER_REDIRECT_URI, client_id: process.env.REACT_APP_NAVER_ID, state: "9asdfas8d09sdf23szx", }); const NAVER_URL = `https://nid.naver.com/oauth2.0/authorize?${params.toString()}` // 지정한 경로로 이동 window.location.href = NAVER_URL; } return ( <Container maxWidth="xs"> <Box mt={5}> <Typography variant="h4" align="center">Login</Typography> <form onSubmit={handleSubmit(onSubmit)}> <TextField fullWidth margin="normal" label="Email" variant="outlined" {...register('email', { required: 'Email is required' })} error={!!errors.email} helperText={errors.email?.message} /> <TextField fullWidth margin="normal" label="Password" type="password" variant="outlined" {...register('password', { required: 'Password is required' })} error={!!errors.password} helperText={errors.password?.message} /> <Button type="submit" variant="contained" color="primary" fullWidth sx={{ mt: 2 }} > Login </Button> <Button fullWidth onClick={() => handleGoogleLogin()}> <img src={google} alt="구글 로그인" width="250" /> </Button> <Button fullWidth onClick={() => handleKakaoLogin()}> <img src={kakao} alt="카카오 로그인" width="250" /> </Button> <Button fullWidth onClick={() => handleGithubLogin()}> <img src={github} alt="깃허브 로그인" width="250" /> </Button> <Button fullWidth onClick={() => handleNaverLogin()}> <img src={naver} alt="네이버 로그인" width="250" /> </Button> </form> </Box> </Container> ); } export default LoginPage;
JavaScript
복사