React


 

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://developers.kakao.com/

https://han-py.tistory.com/417

 

 

 

 

 

 

 

 

 

 

react

 

about author

PHRASE

Level 60  라이트

세상에서 가장 빠른 전차만큼 빨리 달아오르는 분노를 삭히는 사람이야말로 진정 백성과 나라를 다스릴만한 사람이다. 그렇지 않은 사람들은 백성과 나라를 다스릴 만한 자격이 없다. 그들은 단지 고삐만 건성으로 잡고 있는 사람에 불과하기 때문이다. -불교

댓글 ( 4)

댓글 남기기

작성