++세션&쿠키로 로그인 구현

https://codelist.tistory.com/85

 

[Node.js] 세션 구현하기 (express-session)

세션 구현 시도 https://codelist.tistory.com/62 [Vue.js, Node.js] 쿠키로 로그인/로그아웃 구현 여는 글 쿠키는 보안상 좋지 않아서 쿠키만으로는 로그인/로그아웃을 구현하기엔 좋지 않다. 대부분은 세션+

codelist.tistory.com

 

 

여는 글


 

 

쿠키는 보안상 좋지 않아서 쿠키만으로는 로그인/로그아웃을 구현하기엔 좋지 않다.

 

대부분은 세션+쿠키를 사용하는 것 같다.

 

그래서 나도 처음엔 세션부터 구현하려고 했다.

 

세션에는 그냥 메모리에 저장하는 방식, 파일로 저장하는 방식, DB에 저장하는 방식이 있고 실제로는 파일이나 DB에 저장하는 방식이 좋다고 하고 많이 쓰인다고 한다.

 

그래도 일단 세션이 되는 지 안 되는 지 테스트 해볼겸 메모리 저장하는 방식을 택하고 구현을 했는데 안됐다.

 

세션에 값을 저장할 때 KEY를 생성해서 쓰던데, 예를 들어 req.session.user 이런 식으로.

 

근데 나는 user 라는 KEY 생성 자체가 안됐다.

 

그래서 내가 설정을 덜 했나보다, 키를 먼저 명시를 해줘야하나? 라고 생각해서 3일 동안 구글링했는데 다른 사람들은 별도로 명시하지 않고 바로 사용했고 명시하지 않아도 된다는 글도 있어서 그냥 내가 안되는 거구나, 생각하고 그럼 파일에 저장하는 형식으로 바꾸자, 라고 생각한 후 구현하기 시작했다.

 

근데 파일에 저장하는 형식도 안됐다.

 

보통 node.js 하위에 폴더를 생성하고, 로그인 하게되면 그 생성된 폴더 하위에 키나 데이터 등이 저장된 파일이 생기는데 나는 폴더는 생기는 데 파일이 안 생겼다.

 

그래서 DB에 저장하는 방식으로 바꿨다.

 

일단 나는 이미 DB를 쓰고 있기 때문에 구현하기 더 쉬울 것 같다고 생각했는데 로그인하면 값이 DB에 저장은 당연히 된다.

 

원래도 회원가입 때문에 CREATE 기능을 쓰고 있었으니까.

 

근데 세션을 못 쓰니까 로그인 유지를 어떻게 구현할까 고민하다가 쿠키를 사용하기로 했다.

 

쿠키에 값이 존재하면 로그인 된 상태라는 조건으로 구현하는 것으로.

 

그래서 여기까지는 나름 괜찮았다.

 

근데 이제 로그아웃이 문제였다.

 

로그아웃 버튼을 누르면 쿠키는 잘 삭제가 된다.

 

근데 DB에서 로그인할 때 넣은 session 값이 삭제가 안된다.

 

나는 mongoDB 쓰기 때문에 remove, deleteMany, deleteOne 이런 데이터 삭제 함수들을 써야했는데 이거 3개 다 동작하지 않았다.

 

그래서 여러 테스트를 해본 결과 삭제 함수만 동작이 안된다.

 

create, find 다 잘 되는 데 삭제만 안된다.

 

그래서 결론은, 로그인 가지고 일주일을 붙잡고 있었는데 쿠키로만 구현하게 됐다.

 

쿠키에는 보안상 password를 절대 넣어선 안된다.

 

그래서 나도 name을 넣기로 했다.

 

 

 

쿠키로 로그인/로그아웃 구현하기


 

모든 코드는 github에 올려져 있다.

 

 

backend/routes/index.js

router.post('/login', (req, res) => {
  console.log('로그인 중');
  User.find((err, users) => { // 평문끼리비교하는거라 배포시에는 이렇게 하면 안됨 암호화 필수
    users.forEach((list) => {
      if (req.body.id == '' || req.body.password == ''){
        console.log('로그인 불가');
        return;
      }

      if(list.id == req.body.id && list.password == req.body.password) {
          console.log('로그인 성공!');
          res.cookie('session', list.name);
          console.log(req.cookies.session);
          res.redirect('/');

      }else if (list.id != req.body.id && list.password == req.body.password)  {
          console.log('아이디가 틀렸습니다.');

      } else if (list.id == req.body.id && list.password != req.body.password) {
        console.log('비밀번호가 틀렸습니다.');

      } 
    })
  })
})

router.get('/logout', (req, res) => {
  User.find((err, users) => { // 평문끼리비교하는거라 배포시에는 이렇게 하면 안됨 암호화 필수
    users.forEach((list) => {
      if (req.cookies.session == list.name){
        res.clearCookie('session');
        res.redirect('/');
      }
    })
  })

})

 

 

backend/app.js

app.use('/login', userControll);

app.use('/logout', userControll);

 

 

frontend/src/components/LogInPage.vue

<template>
  <div class="loginpage">
      <form action="/login" method="post">
       <h2>LOG IN</h2> <br>
        <input type="text" name="id" placeholder="ID" autofocus pattern="^(?=.*\d)(?=.*[a-z]).{5,15}"> <br>
        <input type="text" name="password" placeholder="PASSWORD" pattern="^(?=.*\d)(?=.*[a-z]).{8,15}"> <br>
        <button @click="login()">LOG IN</button>
    </form>
  </div>
</template>

<script>
export default {
    name : "LogInPage",
        data (){
        return {
            id : '',
            password : '',

        }
    },
    methods : {
        login(){
            this.axios.post('http://localhost:3000/login',  { 
            headers : {
                "Content-Type" : "application/x-www-form-urlencoded"
            },
            id : this.id,
            password : this.password
                
            }).then((response) => { //이 부분이 아예 동작 안함
                    alert(response.data.message); 
                
            
                
            }).catch((error) => {  
                this.error=error    
            
                
            })

        }
    }

}
</script>


<style>

.loginpage {
    display: inline-block;
    width : 50%;
    background-color: #C8D4E0;
    padding: 5%;
    margin-bottom: 5%;
}

.loginpage input {
    margin: 3%;
    height: 30px;
    font-size: large;
}

.loginpage button {
    font-size: large;
    background-color: #7E868E;
    margin-top: 5%;
    width : 15%;
}

@media screen and (max-width:768px){
    .loginpage {
        width : 80%;
    }

    .loginpage input {
        height : 15px;
        font-size : small;
    }

    .loginpage button {
        font-size : small;
        width : 30%;
    }
}

</style>

 

 

frontend/src/components/LogOutPage.vue

<template>
  <div class="logoutpage">
    <form action="/logout" method="get">
        <button @click="logout()">LOG OUT</button>
    </form>
  </div>
</template>

<script>
export default {
    name : "LogOutPage",
        methods : {
        logout(){
            this.axios.get('http://localhost:3000/logout',  { 
                headers : {
                    "Content-Type" : "application/x-www-form-urlencoded"
                },
                    
                }).then((response) => { //이 부분이 아예 동작 안함
                        alert(response.data.message); 
                    
            
                }).catch((error) => {  
                    this.error=error    
                
                    
            })
        }
  }

}
</script>

<style>

</style>

 

페이지 연결은 frontend/router/index.js 에서 하면 된다.

 

 

 

닫는 글


 

내가 원하던 대로 구현하진 못했지만 이번 기회에 세션, 쿠키를 써볼 수 있는 좋은 경험이었다.

 

추후에는 요즘에 많이 쓰는 네이버/카카오 로그인 API를 구현해보고 싶다.

 

나는 자체적으로 회원가입을 구현해버려서 API를 쓰기엔 아까워서 쓰지 못했지만.

 

다음은 결제 기능이다.

 

결제 기능은 또 얼마나 헤매게 될 지 모르겠지만 워낙 구현하고 싶었던 기능이라서 기대된다.