본문 바로가기

블록체인 기반 핀테크 및 응용 SW개발자 양성과정 일기

[49일차 복습] JavaScript & Oauth 기능으로 kakao login 연결하기

반응형

지난 금요일까지 만든 kakao login은 session에 카카오만 들어가 있는 상태↓

    req.session.kakao=user.data;

kakao, naver, google, local server 등등.. 많은 로그인 기능을 연결하려면 각각 사이트마다 주는 결과도 다르기 때문에 하나에 모아서 처리할 예정 

 

1. session에 웹사이트별 구분 속성값 만들어 넣기 

 

server.js

    const authData = {   //authData 변수에 token.data, user.data 값을 객체로 담음 
        ...token.data,
        ...user.data, 
    }

    req.session.authData = {     //session 안에 kakao라는 속성에 authData의 객체값들을 넣음
        ["kakao"]:authData, 
    }
    console.log(req.session);

    res.redirect('/');
});

- authData 라는 변수에 axios로 받아온 결과를 담은 token, user 의 data 값을 비구조 할당문을 이용해서 담음 

- session에 authData라는 속성을 만들어서 안에 ["kakao"] : authData 변수 값을 객체로 담음 

 

console.log(req.session) 을 찍어보면 

Session {
  cookie: { path: '/', _expires: null, originalMaxAge: null, httpOnly: true },
  authData: {
    kakao: {
      access_token: 'CphfrW0WX4zEj8KojpNYhQg',
      token_type: 'bearer',
      refresh_token: '6wHaQCXwHlAHgcQkvYhQg',
      expires_in: 21599,
      scope: 'account_email profile',
      refresh_token_expires_in: 599,
      id: 17392,
      connected_at: '2021-05-21T02:27:37Z',
      properties: [Object],
      kakao_account: [Object]
    }
  }
}

session  cookie 존재 

속성 추가한 authData 안 kakao라는 속성값으로 ...token.data, ...user.data 들이 쭉 - 들어가 있음 

 

req.session... 계속 이렇게 쓰기 복잡하니 간단하게 바꾸기 

req.session => session   /    req.query => query   /   req.query.code => code

app.get('/auth/kakao/callback', async (req, res) => {
    let {session,query} = req; // 추가 1 req안 session, query란 객체가 있는데 저 변수에 담는다. 
    let {code} = query;         // 추가 2 req.query 안 code라는 객체를 담음 
    let token;
    try {
        token = await axios({
            method: 'POST',
            url: 'https://kauth.kakao.com/oauth/token',
            headers: {
                'content-type': 'application/x-www-form-urlencoded'
            },
            data: qs.stringify({
                grant_type: 'authorization_code',
                // 특정 string 넣기 
                client_id: kakao.clientID,
                client_secret: kakao.clientSecret,
                redirectUri: kakao.redirectUri,
                code, //code: req.query.code,         //변경 1 
                //auth/kakao/callback일때 get값으로 준 코드야
            })
            //객체를 string으로 변환 
        })
    } catch (err) {
        res.json(err.data)
    }


//kakao에게 요청 / 
    let user;
    try{
        user = await axios({
            method:"GET",
            url:'https://kapi.kakao.com/v2/user/me',
            headers:{
                Authorization:`Bearer ${token.data.access_token}`
            }
        })
    }catch(err){
        res.json(err.data)
    }
    
    const authData = {
        ...token.data,
        ...user.data, 
    }

    session.authData = {            // req.session -> session 변경 2
        ["kakao"]:authData,
    }
    console.log(session);

    res.redirect('/');
});

 

 

 

비구조 할당문이란?

 

 

 

2. /auth/info & info.html 수정 

 

server.js

app.get('/auth/info',(req,res)=>{
    const provider = Object.keys(req.session.authData)[0]; //or req.session.authData.kakao
    console.log(provider)   //kakao찍힘 
    res.render('info.html');
})

Object.keys() -> 해당 객체의 key값 / 속성이름 (여기서는'kakao') 만 가져옴 

 

switch 문으로 만약 provider 변수의 내용이 kakao라면 ~ 아래 userinfo={ useid에 kakao 값을 넣겠다.}

app.get('/auth/info',(req,res)=>{
    const provider = Object.keys(req.session.authData)[0];
    console.log(provider)

    let userinfo = {}
    switch (provider){
        case 'kakao' : 
        userinfo = {
            userid:req.session.authData[provider].properties.nickname,
        }
        break;
    }

    res.render('info.html',{
        userinfo,
    });
})

 

 

info.html

당신의 id는 {{userinfo.userid}}입니다. 

 

server on -> check 

 

 

 

server.js /auth/info 부분도 authData객체를 변수에 담아 코드 줄이기 

app.get('/auth/info',(req,res)=>{
    const {authData} = req.session;
    const provider = Object.keys(authData)[0]; 

    let userinfo = {}
    switch (provider){
        case 'kakao' : 
        userinfo = {
            userid:authData[provider].properties.nickname,
        }
        break;
    }

    res.render('info.html',{
        userinfo,
    });
})

 

 

 

 

3. 로그인 여부 체크 

middleware 하나 만들어서 /auth/info 로 들어올 때 한번 거치도록 만들기

const authMiddleware = (req,res,next)=>{  // middleware 만듬 -> session.authData가 없으면 
    const {session} = req;
    if(session.authData==undefined){
        console.log('로그인 안되어 있음 ');                   // 요거 출력
        res.redirect('/?msg=로그인 안되어 있습니다.');
    }else{
        console.log('로그인 되어 있음 ');                  //되어 있으면 next() - 계속가 ~ 
        next();
    }
}

app.get('/auth/info',authMiddleware, (req,res)=>{        //(req,res) 전 middleware 입력
    const {authData} = req.session;

auth/info 들어오면 authMiddleware 로 감 -> authMiddleware 변수에 담긴 익명 함수 거쳐서

로그인이 안된경우  redirect -> 이 때 get값으로 msg = 로그인 안되어있습니다. 를 줌 -> 나중에 msg를 사용할 예정 

로그인 된 경우 next() -> /auth/info 아래쪽 다 실행 

 

 

 

4. 카카오 회원 탈퇴 by data

views - index.html 탈퇴 버튼 추가 

<a href="/auth/kakao">카카오 로그인</a>
<a href="/auth/info">회원정보</a>
<a href = "/auth/kakao/unlink">카카오 탈퇴 </a>

 

server.js

app.get('/auth/kakao/unlink',async (req,res)=>{
    const {session} = req;
    const {access_token} = session.authData.kakao;

    console.log(access_token);            //출력 결과 : djsklcenfaseyr8w3hrkejsdfh74

    let unlink;
    try{
        unlink = await axios({
            method:'POST',
            url:'https://kapi.kakao.com/v1/user/unlink',
            headers:{
                Authorization:`Bearer ${access_token}`
            }
        })
    }catch(err){
        res.json(err.data);
    }
    console.log(unlink.data);        //출력 결과 :  {id : 249856349524}
})

 

 

<-  아까  token.data, user.data를 담아 둔 authData 변수 안에 kakao라는 속성값으로 내용들을 넣어둠 

 

요걸 사용해서 access_token 값을 headers에 안보이게 잘 보내서 회원 탈퇴 요청  

 

 

 

console.log(unlink.data)에 찍힌 id 값을 사용 = 요 값은 카카오쪽에 요청보내서 받은 값 

-> 이제 요 값이 local server session에 저장한 id값과 같으면 session에서 삭제 

app.get('/auth/kakao/unlink',async (req,res)=>{
    const {session} = req;
    const {access_token} = session.authData.kakao;

    console.log(access_token);

    let unlink;
    try{
        unlink = await axios({
            method:'POST',
            url:'https://kapi.kakao.com/v1/user/unlink',
            headers:{
                Authorization:`Bearer ${access_token}`
            }
        })
    }catch(err){
        res.json(err.data);
    }
    console.log(unlink.data);

    const {id} = unlink.data;
    if(session.authData['kakao'].id==id){
        delete session.authData;
    }
    
    res.redirect('/?msg=로그아웃 되었습니다');
})

 

server on -> check - 회원 탈퇴는 되지만 아직 msg = 로그아웃 되었습니다. 부분이 안나옴 

 

 

 

5. msg get값으로 보낸거 alert 만들기 

 

server.js ('/', ()=>{}) 부분에 get값 받는 변수 설정, render 에 함께 보내기 

app.get('/', (req, res) => {
    const {msg} = req.query;
    res.render('index.html',{
        msg,
    });
})

 

views- index.html

<a href="/auth/kakao">카카오 로그인</a>
<a href="/auth/info">회원정보</a>
<a href = "/auth/kakao/unlink">카카오 탈퇴 </a>


{% if msg %}
<script type = "text/javascript">
    alert ("{{msg}}")
</script>
{% endif %}

 

server on -> check -> 카카오 탈퇴 후 '로그아웃 되었습니다' alert 뜸. 그리고 로그인안하고 회원정보 보기 볼 때 도 get값으로 msg 넘긴 '로그인이 안되어 있습니다' alert 도 뜸. msg 라는 key로 맞추고, ('/') 을 다 향하게 해서 훨씬 수월해짐

 

 

카카오톡 비로그인 상태에서 카카오 탈퇴를 누르면 msg 가 뜨도록 아까 만든 middleWare를

/auth/kakao/unlink 쪽에도 넣기 

app.get('/auth/kakao/unlink', authMiddleware, async (req,res)=>{

 

 

 

 


 

 

 

 

 

6. local login 만들기 

views - index.html 

/login a 링크 버튼 추가 

<a href="/auth/kakao">카카오 로그인</a>
<a href="/login">로그인</a>
<a href="/auth/info">회원정보</a>
<a href = "/auth/kakao/unlink">카카오 탈퇴 </a>


{% if msg %}
<script type = "text/javascript">
    alert ("{{msg}}")
</script>
{% endif %}

server.js 

/login get 추가

app.get('/login',(req,res)=>{
   res.render('login.html'); 
})

views - login.html 생성 / 코드 작성

<form method="post" action="/login">
    <input type="text" name="userid">
    <input type="password" name="userpw">
    <input type="submit" value="로그인">
</form>

 

Post 사용 - > body-parser 설치 및 코드 작성 

$npm install body-parser 

const bodyParser = require('body-parser');

app.use(bodyParser.urlencoded({extended:false}));

 

 

server.js /login post 부분 작성  (db 처리 되었다고 가정) 

app.post('/login', (req,res)=>{
    const {session,body} = req;
    const {userid,userpw} = body;

    if(userid=='root' && userpw =='root'){
        const data = {
            userid,
        }
        session.authData={
            ["local"]:data,
        }

        res.redirect('/?msg=로그인 되었습니다.');
    }else{
        res.redirect('/?msg=아이디와 패스워드를 확인해주세요');
    }
})

 

 

local 로 로그인 시 '회원정보' 나오게 수정하기 

server.js /auth/info

app.get('/auth/info',authMiddleware, (req,res)=>{
    const {authData} = req.session;
    const provider = Object.keys(authData)[0];

    let userinfo = {}
    switch (provider){
        case 'kakao' : 
        userinfo = {
            userid:authData[provider].properties.nickname,
        }
        break;
        case 'local' : 
        userinfo={
            userid:authData[provider].userid,
        }
        break;
    }

    res.render('info.html',{
        userinfo,
    });
})

 

local login 로그아웃 만들기 - 하나의 버튼으로 둘다 로그아웃 가능하게 만들기 

index.html logout 버튼 추가 / 카카오탈퇴 버튼 주석 

{% if loginInfo==undefined %}
<a href="/auth/kakao">카카오 로그인</a>
<a href="/login">로그인</a>
{% else %}
<a href="/auth/info">회원정보</a>
<a href="/auth/logout"> 로그아웃 </a>
<!--<a href = "/auth/kakao/unlink">카카오 탈퇴 </a>-->
{% endif %}

{% if msg %}
<script type = "text/javascript">
    alert ("{{msg}}")
</script>
{% endif %}

 

 

server.js /auth/logout 만들기 (kakao, local 로그인인지 구분해서) 

server.js

app.get('/auth/logout', (req,res)=>{
    const {session} = req;
    const {authData} = session; 
    const provider = Object.keys(authData)[0];

    switch(provider){
        case 'local' : 
            delete session.authData;
            res.redirect('/?msg=로그아웃 되었습니다.');
        break;
        case 'kakao' : 
            res.redirect('/auth/kakao/unlink');
        break;
    }
})

server on -> check 

 

 

 

7. 로그인했을 때, 안했을 때 (session 값이 있을 때, 없을 때) 보이는 버튼 구분하기

server.js

app.get('/', (req, res) => {
    const {msg} = req.query;
    res.render('index.html',{
        msg,
        loginInfo:req.session.authData,    // 추가
    });
})

카카오 로그인 -> local 로그인 하면 login 이 덮어 씌여짐 이 경우 따로따로 코드 작성을 하는게 좋지만 시간 여유없으면 둘 중 하나로 로그인 시 다시 로그인 버튼 안보이게 만들면 됨 

 

index.html

{% if loginInfo==undefined %}
<a href="/auth/kakao">카카오 로그인</a>
<a href="/login">로그인</a>
{% else %}
<a href="/auth/info">회원정보</a>
<a href = "/auth/kakao/unlink">카카오 탈퇴 </a>
{% endif %}

{% if msg %}
<script type = "text/javascript">
    alert ("{{msg}}")
</script>
{% endif %}

server on -> check 

 

 

반응형