소셜 로그인 구현 프로젝트 - 기존 미니 이커머스 프로젝트 파일에서 진행
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
복사

