Config.js
export const HOST = "http://localhost:3000";
export const KAKAO_CLINT_ID = "카카오 클라이언트 ID";
export const KAKAO_CALLBACK_URL = `${HOST}/oauth/callback/kakao`;
export const KAKAO_AUTH_URL = `https://kauth.kakao.com/oauth/authorize?client_id=${KAKAO_CLINT_ID}&redirect_uri=${KAKAO_CALLBACK_URL}&response_type=code`;
export const NAVER_CLIENT_ID = "네이버 클라이언트 아이디"; // 발급 받은 Client ID 입력
export const NAVER_CALLBACK_URL = `${HOST}/oauth/callback/naver`; // 작성했던 Callback URL 입력
URL 설정
App.js
~
<Route path="/oauth/callback/kakao" element={<AuthKakaoLoginHandler />} />
<Route path="/oauth/callback/naver" element={<AuthNaverLoginHandler />} />
KakaoLoginHandler.js
import React, { useEffect } from "react";
import { useDispatch } from "react-redux";
import { useNavigate } from "react-router-dom";
import { loginUserKakao } from "../../../_actions/user_actions";
import { KAKAO_CLINT_ID, KAKAO_CALLBACK_URL } from "../../Config";
import axios from 'axios';
const KakaoLoginHandler = () => {
const dispatch = useDispatch();
const naigate = useNavigate();
const params = new URL(document.location.toString()).searchParams;
const code = params.get("code"); // 인가코드 받는 부분
const grant_type = "authorization_code";
useEffect(() => {
if (code) {
kakaoLoginProcess();
}
}, []);
//1.카카오 access_token 값 가져오기
async function getKakoAccessToken() {
return await axios.post(
`https://kauth.kakao.com/oauth/token?grant_type=${grant_type}`
+ `&client_id=${KAKAO_CLINT_ID}&redirect_uri=${KAKAO_CALLBACK_URL}&code=${code}`
, {
headers: {
'Content-type': 'application/x-www-form-urlencoded;charset=utf-8',
}
}).then((res) => {
return res.data.access_token;
}).catch(err => {
naigate("/");
console.log(" error : ", err);
})
}
//2. access_token 값을 이용하여 카카오 로그인 유저정보 값가져오기
async function getKakoUserInfo() {
const ACCESS_TOKEN = await getKakoAccessToken();
console.log("ACCESS_TOKEN : ", ACCESS_TOKEN);
return await axios.post("https://kapi.kakao.com/v2/user/me", {
property_keys: "kakao_account.email"
}, {
headers: {
"Content-Type": "application/x-www-form-urlencod",
"Authorization": `Bearer ${ACCESS_TOKEN}`
}
}).then((res) => {
return res.data.kakao_account;
});
}
//3.카카오 정보를 이용해서 서버에 로그인 처리
async function kakaoLoginProcess() {
const kakoUserInfo = await getKakoUserInfo();
if (!kakoUserInfo.email) {
alert("이메일 정보 제공은 필수 입니다.");
return;
}
let dataToSubmit = {
email: kakoUserInfo.email,
name: kakoUserInfo.profile.nickname,
image: kakoUserInfo.profile.thumbnail_image_url,
oauth2: "kakao"
};
console.log("dataToSubmit : ", dataToSubmit);
//4. 카카오에서 받은 정보를 서버로 데이터를 넘겨주어 로그인 처리를 한다.
//다음은 nodejs 서버로 데이터를 넘겨주는 코드 ,, 개발 환경에 맞게 처리~
dispatch(loginUserKakao(dataToSubmit))
.then(response => {
if (response.payload.loginSuccess) {
window.localStorage.setItem('userId', response.payload.userId);
console.log("loginSuccess :", response.payload);
naigate("/");
} else {
console.log("로그인 실패 :");
}
})
.catch(err => {
console.log("에러 :", err);
});
}
return (
<div>
{/* 사실 이페이지는 크게 의미 없다. 첫화면으로 로직이 끝나면 이동시켜주면 된다. */}
</div>
);
};
export default KakaoLoginHandler;
로그인 페이지에서
KAKAO_AUTH_URL 링크 처리 해주면된다.
디자인은 환경에 맞게
LoginPage.js
import React, { useState } from "react";
import { Link, useNavigate } from "react-router-dom";
import './LoginPage.css';
import NaverLoginHandler from './../Oauth2/NaverLoginHandler';
import { KAKAO_AUTH_URL } from "../../Config";
const { Title } = Typography;
function LoginPage(props) {
~
~
return (
return (
<div className="app">
<Form.Item required>
~
{/* 카카오 로그인 버튼 */}
<a style={{
marginTop: "20px", height: 50,
backgroundColor: "#fee500", position: "relative", textAlign: "center",
borderRadius: "3px", cursor: "pointer", fontWeight: 600, display: "block",
color: "#000"
}} href={KAKAO_AUTH_URL} className="kakoBtn" >
<span className="kakao_btn"><span className="icon"></span>
<span className="kakao_txt"> 카카오 로그인</span>
</span>
</a>
~
</Form.Item>
</form>
</div>
);
}}
</Formik >
);
};
export default LoginPage;
LoginPage.css
.kakoBtn{
border-radius: 5px;
}
.kakao_btn{
width: 318px;
}
.kakao_btn .icon {
background:url("./icon_kakao.png") no-repeat !important;
position: absolute;
top: 5px;
left: 10px;
line-height: 45px;
width: 40px;
height: 38px;
}
.kakao_btn .kakao_txt {
position: absolute;
top: 5px;
left: 135px;
}
.type01 {margin-top:50px}
.type02 {margin-top:44px} /* 893 */
.type03 {margin-top:40px}
.a {display:block;margin-top:10px;width:100%;height:50px;border:1px solid #000;font-size:15px;line-height:50px;text-align:center;background:#fff} /* 893 */
.a.type01 {background-color:#fff}
.a.type01>span {color:#333}
.a.facebook {border-color:#405ea9}
.a.naver {border-color:#2db400}
.a.kakao {border-color:#3a2020}
.a.google {border-color:#3e82f1}
.a.apple {border-color:#000}
.a:first-child {margin-top:0}
.a>.icon {display:inline-block;margin:0 auto;padding-left:29px;width:188px;color:#666;font-size:15px;letter-spacing:-1px;line-height:20px;text-align:left}
.a.facebook>.icon {background:url("https://cdn.jsdelivr.net/gh/braverokmc79/ouath2-img@v1.0.0/images/icon_facebook.png") no-repeat 0 0;background-size:18px auto}
.a.naver>.icon {background:url("https://cdn.jsdelivr.net/gh/braverokmc79/ouath2-img@v1.0.0/images/icon_naver.png") no-repeat 0 0;background-size:18px auto}
.a.kakao>.icon {background:url("https://cdn.jsdelivr.net/gh/braverokmc79/ouath2-img@v1.0.0/images/icon_kakao.png") no-repeat 0 0;background-size:18px auto}
.a.google>.icon {background:url("https://cdn.jsdelivr.net/gh/braverokmc79/ouath2-img@v1.0.0/images/icon_google.png") no-repeat 0 0;background-size:18px auto}
.a.apple>.icon {background:url("https://cdn.jsdelivr.net/gh/braverokmc79/ouath2-img@v1.0.0/images/icon_apple.png") no-repeat 0 0;background-size:20px auto}
.a.phone>.icon {background:url("https://cdn.jsdelivr.net/gh/braverokmc79/ouath2-img@v1.0.0/images/icon_phone.png") no-repeat 0 0;background-size:18px auto}
.a.email>.icon {background:url("https://cdn.jsdelivr.net/gh/braverokmc79/ouath2-img@v1.0.0/images/icon_email.png") no-repeat 0 0;background-size:18px auto}
.seller_change_guide {margin-top:44px;width:100%;height:84px;color:#fff;font-family:NotoSansCJKkr, sans-serif;font-size:12px;font-weight:normal;font-style:normal;font-stretch:normal;letter-spacing:-0.8px;line-height:1.6;background-color:#55abfa}
.seller_change_guide img {display:inline-block;margin:-1rem -1.6rem -1rem -1rem;transform:scale(0.55)}
.seller_change_guide h4 {font-size:14px;font-weight:bold;letter-spacing:-0.9px}
.seller_change_guide div {display:inline-block;margin-top:0;margin-left:0;width:73%;vertical-align:middle;word-break:keep-all}
.seller_change_guide div u {position:relative;text-decoration:none}
.seller_change_guide div u:after {position:absolute;bottom:-2px;left:0;width:100%;border-width:0 0 1px;border-style:solid;border-color:#fff;content:""}
.ant-input-affix-wrapper .ant-input:not(:first-child) {
padding-left: 30px;
height: 50px;
margin-bottom: 20px;
}
.ant-input-affix-wrapper .ant-input-prefix {left: 12px;}
.ant-input-affix-wrapper .ant-input-prefix, .ant-input-affix-wrapper .ant-input-suffix { top: 34%;}
#naverIdLogin {
margin-top: 20px;
margin-bottom: 20px;
}
#naverIdLogin , #naverIdLogin_loginButton , #naverIdLogin_loginButton img{
width: 350px !important;
}
.app{
height: 77vh;
}
nodjs 로그인 참조
/**5. 카카오 로그인 처리 */
router.post("/login/kakao", (req, res) => {
//1)요청한 이메일을 DB 에서 찾는다.
User.findOne({ email: req.body.email }, (err, user) => {
if (!user) {
//2)등록 처리
const user = new User(req.body);
console.log("저장할 user :", user);
user.save((err, doc) => {
if (err) return res.json({ success: false, err });
console.log("등록 처리 후 Token 생성 ");
// Token 생성
user.generateToken((err, user) => {
if (err) return res.status(400).send(err);
//토큰을 쿠키에 저장한다.
res.cookie("w_authExp", user.tokenExp);
res.cookie("w_auth", user.token)
.status(200)
.json({
loginSuccess: true,
userId: user._id
});
});
});
return;
}
//5)등록된 유저가 있다면 바로 Token 생성
user.generateToken((err, user) => {
if (err) return res.status(400).send(err);
//6)토큰을 쿠키에 저장한다.
res.cookie("w_authExp", user.tokenExp);
res.cookie("w_auth", user.token)
.status(200)
.json({
loginSuccess: true,
userId: user._id
});
});
});
});
이미지 다운로드
https://github.com/braverokmc79/ouath2-img
참조 :
https://han-py.tistory.com/417













댓글 ( 4)
댓글 남기기