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)
댓글 남기기