관리 메뉴

SIMPLE & UNIQUE

4-2강 : 로그인 기능 구현, 쿠키로 로그인 세션 관리 본문

탈잉 강의 자료/2020_비전공자도 가능한 웹 프로젝트

4-2강 : 로그인 기능 구현, 쿠키로 로그인 세션 관리

착한코딩 2020. 8. 3. 23:32

4_2강 소스.zip
0.53MB
4_2강 소스_덮어쓰기.zip
0.27MB

4_2 목표 : 회원가입에 사용한  bcrypt패키지를 사용해, 로그인 비밀번호를 회원정보에 저장된 비밀번

호와 비교한다. 로그인이 완료되면 쿠키에 회원정보를 저장하고, 관리한다.

 

1. 로그인을 구현해, 그 결과에 따라 유효성을 체크하고 동작을 다르게 처리한다.

 

1) react 경로 C:\react200\client 에 쿠키 패키지 react-cookies를 설치한다.

npm install react-cookies --save

2) react 경로 C:\react200\client\src\components에 있는 LoginForm.js를 아래와 같이 수정한다.

import React, { Component } from 'react';
import {Redirect, Link} from 'react-router-dom'
import cookie from 'react-cookies';
import $ from 'jquery';
import axios from "axios";
import Swal from 'sweetalert2'

class LoginForm extends Component {
    constructor (props) {
        super(props);

        this.state = {
            prop:props
        }
    }
    submitClick = async e => {
        this.email_val = $('#email_val').val();
        this.pwd_val = $('#pwd_val').val();
        if(this.email_val === '' || this.pwd_val === ''){
            this.sweetalert('이메일과 비밀번호를 확인해주세요.', '', 'info', '닫기')
        }else{
            axios.post('/api/LoginForm?type=signin', {
                is_Email: this.email_val,
                is_Password: this.pwd_val
            })
            .then( response => {
                try {
                    var userid = response.data.json[0].useremail
                    var username = response.data.json[0].username
                    var userflag = response.data.json[0].userflag
                    var upw = response.data.json[0].userpassword
                    
                    if(userid != null && userid != ''){
                        this.sweetalert('로그인 되었습니다.', '', 'info', '닫기')
                        //로그인 id 세션에 저장
                        const expires = new Date()
                        expires.setMinutes(expires.getMinutes() + 60)
                        
                        //userid 와 username을 비밀키로 암호화해 쿠키값에 세팅한다.
                        axios.post('/api/LoginForm?type=SessionState', {
                            is_Email: userid,
                            is_UserName: username,
                        })
                        .then( response => {

                            cookie.save('userid', response.data.token1
                            , {
                                path: '/',
                                expires,
                                // httpOnly: true // 도메인 연결 후 주석해제
                            })
                            cookie.save('username', response.data.token2
                            , {
                                path: '/',
                                expires,
                                // httpOnly: true // 도메인 연결 후 주석해제
                            })

                            cookie.save('userpassword', upw
                            , {
                                path: '/',
                                expires,
                                // httpOnly: true // 도메인 연결 후 주석해제
                            })
                            cookie.save('user_flag', 'Y'
                                , {
                                    path: '/',
                                    expires
                                }
                            );
                        })  
                        .catch( error => {this.sweetalert('작업중 오류가 발생하였습니다.', error, 'error', '닫기'); return false; } );
                        
                        setTimeout(function() {
                            window.location.href = '/';
                        }.bind(this),1000
                        );

                    }else{
                        this.sweetalert('이메일과 비밀번호를 확인해주세요.', '', 'info', '닫기')
                    }
                } catch (error) {
                    this.sweetalert('이메일과 비밀번호를 확인해주세요.', '', 'info', '닫기')
                }
            })
            .catch( response => { alert(response);return false; } );
        }
    }

    // input value state
    handleChange = (e) => {
        this.setState({
            [e.target.name]: e.target.value
        })
    }

    // login form post
    handleSubmit = (e) => {
        // submit 페이지 리로딩 방지
        e.preventDefault();
    }

    // 비밀번호 재설정
    pwdResetClick = () => {
        $('.m_login').hide();
        $('.m_pw').fadeIn();
        $('.m_pw').css('display','table-cell');
    }

    //비밀전호 재설정용 메일 발송
    sendEmail = (email, subject, text, e) => {
        axios.post('/api/message?type=email&roll=resetpw', {
            is_Email : email,
            is_Subject : subject,
            is_Text: text
        })
        .then( response => {
            this.sweetalert('입력하신 이메일로 비밀번호 \n 재설정 메일 보내드렸습니다.', '', 'info', '닫기')
        })
        .catch( error => {this.sweetalert('작업중 오류가 발생하였습니다.', error, 'error', '닫기');return false;});
    }

    // //비밀번호 재설정 확인버튼
    pwdResetConfim = (e) => {
        this.reset_email = $('#reset_email_val').val();
        this.reset_name = $('#reset_name_val').val();
        if(this.reset_email === '' || this.reset_name === ''){
            this.sweetalert('이메일과 성명을 확인해주세요.', '', 'info', '닫기')
        }else{
            axios.post('/api/LoginForm?type=pwreset', {
                is_Email: this.reset_email,
                is_Name: this.reset_name,
            })
            .then( response => {
                var userid = response.data.json[0].useremail
                var username = response.data.json[0].username
                var userpassword = response.data.json[0].userpassword

                if(userid != null && userid != ''){
                    this.sendEmail(userid, 'rtrod 비밀번호 재설정 메일', userpassword)
                }else{
                    this.sweetalert('이메일과 성명을 확인해주세요.', '', 'info', '닫기')
                }
            })
            .catch( response => {this.sweetalert('이메일과 성명을 확인해주세요.', '', 'info', '닫기');return false; } );
        }
    }

    //alert 기본 함수
    sweetalert = (title, contents, icon, confirmButtonText) => {
        Swal.fire({
            title: title,
            text: contents,
            icon: icon,
            confirmButtonText: confirmButtonText
          })
    }

    render () {
        return (
            <section className="main">
            {/* <!-- 로그인폼 --> */}
                <div className="m_login">
                <h3><span><img src={require("../img/main/log_img.png")} alt="" /></span>LOGIN</h3>
                <div className="log_box">
                    <form onSubmit={this.handleSubmit}>
                    <div className="in_ty1">
                        <span><img src={require("../img/main/m_log_i3.png")} alt="" /></span>
                        <input type="text" id="email_val" name="email" placeholder="이메일" onChange={this.handleChange} />
                    </div>
                    <div  className="in_ty1">
                        <span className="ic_2"><img src={require("../img/main/m_log_i2.png")} alt="" /></span>
                        <input type="password" id="pwd_val" name="password" placeholder="비밀번호" onChange={this.handleChange} />
                    </div>
                    <ul className="af">
                        <li><Link to={'/register_check'}>회원가입</Link></li>
                        <li className="pwr_b" onClick={this.pwdResetClick}><a href="#n">비밀번호 재설정</a></li>
                    </ul>
                    {/* <input className="s_bt" type="submit" value="로그인" />	 */}
                    <button className="s_bt" type="submit" onClick={this.submitClick}>로그인</button>
                    </form>
                </div>
                </div>
            {/* <!-- 비밀번호 재설정 --> */}
                <div className="m_login m_pw">
                <h3 className="pw_ls">비밀번호 재설정 <span className="compl1">완료</span></h3>
                <div className="log_box">
            {/* <!-- 1단 --> */}
                    {/* <form method="post"> */}
                    <div className="pw_one">
                        <div className="in_ty1">
                        <span><img src={require("../img/main/m_log_i3.png")} alt="" /></span>
                        <input type="text" id="reset_email_val" name="" placeholder="이메일"/>
                        </div>
                        <div  className="in_ty1">
                        <span className=""><img src={require("../img/main/m_log_i1.png")} alt="" /></span>
                        <input type="text" id="reset_name_val" name="" placeholder="성명"/>
                        </div>
                        <div className="btn_confirm btn_confirm_m">
                        <div className="bt_ty bt_ty_m bt_ty1 cancel_ty1" onClick={this.pwdResetCancleClick}>취소</div>
                        <a href="#n" className="bt_ty bt_ty_m bt_ty2 submit_ty1" onClick={this.pwdResetConfim}>확인</a>
                        </div>
                    </div>
            {/* <!-- 2단 가려둠-->  */}
                    <div className="pw_two">
                        <div className="in_ty1">
                        <span className="ic_2"><img src={require("../img/main/m_log_i2.png")} alt="" /></span>
                        <input type="password" name="" placeholder="새 비밀번호" />
                        </div>
                        <div className="in_ty1">
                        <span className="ic_2"><img src={require("../img/main/m_log_i2.png")} alt="" /></span>
                        <input type="password" name="" placeholder="새 비밀번호 확인" />
                        </div>
                        <div className="btn_confirm btn_confirm_m">
                        <div className="bt_ty bt_ty_m bt_ty1 cancel_ty1">취소</div>
                        <a href="#n" className="bt_ty bt_ty_m bt_ty2 submit_ty1">재설정</a>
                        </div>
                    </div>
            {/* <!-- 3단 가려둠 --> */}
                    <div className="pw_tree">
                        <div className="">
                        <p>
                            '<span>홍길동</span>'
                            님의 비밀번호가 재설정되었습니다.
                        </p>		
                        
                        </div>
                        <input className="s_bt" type="submit" value="로그인 이동" />	
                    </div>
                    {/* </form> */}
                </div>
                </div>
                
            </section>
        );
    }
}

LoginForm.defaultProps = {
}

export default LoginForm;

2) react 경로 C:\react200\client\src\components에 있는 App.js를 아래와 같이 수정

import React, { Component } from 'react';
import { Route } from "react-router-dom";
import cookie from 'react-cookies';
import axios from "axios";

// css
import '../css/new.css';

// header
import HeaderAdmin from './Header/Header admin';

// footer
import Footer from './Footer/Footer';

// login
import LoginForm from './LoginForm';

import SoftwareList from './SoftwareToolsManage/SoftwareList';
import SoftwareView from './SoftwareToolsManage/SoftwareView';

import Register from './Register/Register';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
    }
  }

  componentDidMount() {
    axios.post('/api/LoginForm?type=SessionConfirm', {
      token1 : cookie.load('userid') 
      , token2 : cookie.load('username') 
    })
    .then( response => {
        this.state.userid = response.data.token1
        let password = cookie.load('userpassword')
        if(password !== undefined){
          axios.post('/api/LoginForm?type=SessionSignin', {
            is_Email: this.state.userid,
            is_Token : password
          })
          .then( response => {
            if(response.data.json[0].useremail === undefined){
              this.noPermission()
            }
          })
          .catch( error => {
            this.noPermission()
          });
        }else{
          this.noPermission()
        }
    })
    .catch( response => this.noPermission());
  }

  noPermission = (e) => {
    if(window.location.hash != 'nocookie'){
      this.remove_cookie();
      window.location.href = '/login/#nocookie';
    }
  };

  remove_cookie = (e) => {
    cookie.remove('userid', { path: '/'});
    cookie.remove('username', { path: '/'});
    cookie.remove('userpassword', { path: '/'});
  }

  render () {
    return (
      <div className="App">
        <HeaderAdmin/> 
        <Route exact path='/' component={LoginForm} />
        <Route path='/login' component={LoginForm} />
        <Route path='/SoftwareList' component={SoftwareList} />
        <Route path='/SoftwareView/:swtcode' component={SoftwareView} />
        <Route path='/register' component={Register} />
        <Footer/>
      </div>
    );
  }
}

export default App;

 

3) 로그아웃 처리를 위해 react 경로 C:\react200\client\src\components\Header

에 있는 Header admin.js를 아래와 같이 수정한다.

import React, {Component} from 'react';
import { Link } from 'react-router-dom';
import axios from "axios";
import cookie from 'react-cookies';
import $ from 'jquery';
import Swal from 'sweetalert2';


class Header extends Component {
    constructor(props) {
        super(props);
        this.state = {
            usernm:'',
        };
    }
    componentDidMount() {
        var cookie_userid = cookie.load('userid')
        var cookie_usernm = cookie.load('username')
        var cookie_password = cookie.load('userpassword')

        if(cookie_userid != undefined){
            const expires = new Date()
            expires.setMinutes(expires.getMinutes() + 60)

            cookie.save('userid', cookie_userid
            , { path: '/', expires })
            cookie.save('username', cookie_usernm
            , { path: '/', expires })
            cookie.save('userpassword', cookie_password
            , { path: '/', expires })

            $('.menulist').show()
            $('.hd_top').show()
        }else{
            $('.menulist').hide()
            $('.hd_top').hide()
        }
        this.callSessionInfoApi()
    }

    callSessionInfoApi = (type) => {
        axios.post('/api/LoginForm?type=SessionConfirm', {
            token1 : cookie.load('userid') 
            , token2 : cookie.load('username') 
        })
        .then( response => {
            this.setState({usernm : response.data.token2})
        })
        .catch( error => {
            this.sweetalert('작업중 오류가 발생하였습니다.', error, 'error', '닫기');
        });
    }

    sweetalert = (title, contents, icon, confirmButtonText) => {
        Swal.fire({
            title: title,
            text: contents,
            icon: icon,
            confirmButtonText: confirmButtonText
          })
    }

    myInfoHover () {
        $(".hd_left > li > .box1").stop().fadeIn(400);
    }
    
    myInfoLeave () {
        $(".hd_left > li > .box1").stop().fadeOut(400);
    }

    logout = async e => {
        cookie.remove('userid', { path: '/'});
        cookie.remove('username', { path: '/'});
        cookie.remove('userpassword', { path: '/'});
        window.location.href = '/login';
    }

    render () {
        return(
            <header className="gnb_box">
            <div className="hd_top">
                <div className="top_wrap ct1 af">
                <ul className="hd_left af">
                <li className="my1" onMouseEnter={this.myInfoHover}
                onMouseLeave={this.myInfoLeave}><b>내정보</b>
                        <div className="box0 box1">
                            <ul>
                            <li><a>내 정보 수정</a></li>
                            <li><a href="javascript:" onClick={this.logout}>로그아웃</a></li>
                            </ul>
                        </div>
                        </li>
                    <li className="my2"><b><span>0</span>알림</b>
                    </li>
                </ul>
                <div className="hd_right">
                    <p><span>'{this.state.usernm}'</span>님 반갑습니다.</p>
                </div>
                </div>
            </div>
                <div className="h_nav ct1 af">
                    <div className="logo">
                        <Link to={'/'}><img src={require("../../img/layout/logo.jpg")} height="65px" width="200px" alt=""/></Link>
                    </div>
                    <nav className="gnb gnb_admin">
                    <ul className="af">
                        <li className="menulist">
                            <Link to={'/UserApproval'}>사용자 관리</Link>
                        </li>
                        <li className="menulist">
                            <Link to={'/AdminResearchProject'}>Research Projects 관리</Link>
                        </li>
                        <li className="menulist">
                            <Link to={'/SoftwareList'}>Software Tools 관리</Link>
                        </li>
                        <li className="menulist">
                            <Link to={'/AdminDataSourceList'}>Data Sources 관리</Link>
                        </li>
                        {/* 드롭다운 이벤트 */}
                        <li  className="menulist"><Link to={'/floatPopulationList'}>유동인구 조회</Link>
                        <ul className="gn_2">
                            <li><Link to={'/community/notice'}>공지사항</Link></li>
                        </ul>
                        </li>
                        <li  className="menulist">
                            <Link to={'/SubCodeManage'}>Sub code 관리</Link>
                        </li>
                    </ul>
                    </nav>
                </div>
            </header>
        );
    }
}

export default Header;

## 참고 ##

  이 상태에서 로그인이 정상적으로 되면 softwaretool 리스트 페이지로 이동하고, 로그아웃을 하면 다시 로그인 페이지로 이동한다. 로그아웃 상태에서는 페이지 진입을 막기위해 헤더를 hide() 처리했다.

2. node 경로(C:\react200)에 회원가입관련 코드를 추가한다.

1) server.js 파일을 아래와 같이 수정한다.

var express = require('express');

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var swtoolRouter = require("./routes/SwtoolRout");
var fileuploadRouter = require("./routes/UploadRout");
var usersRouter = require("./routes/UsersRout");
require("./routes/BatchRout");

var app = express();

app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use("/api/Swtool", swtoolRouter);
app.use("/api/upload", fileuploadRouter);
app.use(express.static("./uploads"));
app.use("/api/register", usersRouter);
app.use("/api/LoginForm", usersRouter);

const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`Listening on port ${port}`));

2) 로그인 세션 관리를 위해 사용할 jsonwebtoken 패키지를 설치한다.

npm install jsonwebtoken --save

3) 노드경로 C:\react200에 ignorefile 폴더를 생성하고, jwt.js 파일을 생성해 아래 코드를 붙여넣는다. 아래 react200 문자열이 비밀키인데, 아무 문자열이든 상관없지만 유출되지 않도록 조심한다. git을 사용할 때도 예외처리 해줘야한다.

let jwtObj = {};
jwtObj.secret = "react200"
module.exports = jwtObj

4) 노드경로 C:\react200\routes에  UsersRout.js 파일에 아래 코드를 붙여넣는다.

var express = require('express');
var router = express.Router();
const bodyParser = require('body-parser');

const bcrypt = require('bcrypt');
const saltRounds = 10;

let jwt = require("jsonwebtoken");
let secretObj = require("../ignorefile/jwt");

router.use(bodyParser.json());
router.use(bodyParser.urlencoded({ extended: true }));

router.post('/', (req, res, next) => {
    var type = req.query.type;
    if(type == "signup"){
      //회원가입 정보 삽입
      try {
        // Mysql Api 모듈(CRUD)
        var dbconnect_Module = require('./dbconnect_Module');
    
        //Mysql 쿼리 호출정보 입력
        req.body.mapper = 'UserMapper';//mybatis xml 파일명
        req.body.crud = 'insert';//select, insert, update, delete 중에 입력
        req.body.mapper_id = 'insertUser';
    
        var myPlaintextPassword = req.body.is_Password;
        if(myPlaintextPassword != '' && myPlaintextPassword != undefined ){
          bcrypt.genSalt(saltRounds, function(err, salt) {
            bcrypt.hash(myPlaintextPassword, salt, function(err, hash) {
              req.body.is_Password = hash;
              router.use('/', dbconnect_Module);
              next('route')
            });
          });
        }else{
          router.use('/', dbconnect_Module);
          next('route')
        }
      } catch (error) {
        console.log("Module > dbconnect error : "+ error);      
      }
    }else if(type == "dplicheck"){
      //이메일 중복체크
      try {
        // Mysql Api 모듈(CRUD)
        var dbconnect_Module = require('./dbconnect_Module');
    
        //Mysql 쿼리 호출정보 입력
        req.body.mapper = 'UserMapper';//mybatis xml 파일명
        req.body.crud = 'select';//select, insert, update, delete 중에 입력
        req.body.mapper_id = 'selectUserDpliCheck';
        router.use('/', dbconnect_Module);
        next('route')
      } catch (error) {
        console.log("Module > dbconnect error : "+ error);      
      }
    }else if(type == "signin"){
      //로그인 조회
      try {
        // Mysql Api 모듈(CRUD)
        var dbconnect_Module = require('./dbconnect_Module');
    
        //Mysql 쿼리 호출정보 입력
        req.body.mapper = 'UserMapper';//mybatis xml 파일명
        req.body.crud = 'select';//select, insert, update, delete 중에 입력
        req.body.mapper_id = 'selectLoginCheck';
    
        router.use('/', dbconnect_Module);
        next('route')
        
      } catch (error) {
        console.log("Module > dbconnect error : "+ error);      
      }
    }else if(type == "SessionState"){
      var userid = req.body.is_Email
      var name = req.body.is_UserName
      try {
        let token1 = jwt.sign(
        { email: userid },
        secretObj.secret,
        { expiresIn: '60m' })
       
        let token2 = jwt.sign(
        { username: name },
        secretObj.secret,
        { expiresIn: '60m' })
        res.send({"token1":token1, "token2":token2});
      } catch (error) {
        res.send(error)
      }
    }else if(type == "SessionConfirm"){
      try {
        let token1 = req.body.token1;
        let token2 = req.body.token2;
        
        if(token1 != undefined && token1 != '' & token2 != undefined && token2 != ''){
          let decoded1 = jwt.verify(token1, secretObj.secret);
          let decoded2 = jwt.verify(token2, secretObj.secret);
          res.send({"token1":decoded1.email, "token2":decoded2.username});
        }else{
          res.send({"token1":"", "token2":""});
        }
      } catch (error) {
        res.send(error)
      }
    }else if(type == "SessionSignin"){
      // 쿠키 정보로 사용자 인증 
      try {
        // Mysql Api 모듈(CRUD)
        var dbconnect_Module = require('./dbconnect_Module');
        //Mysql 쿼리 호출정보 입력
        req.body.mapper = 'UserMapper';//mybatis xml 파일명
        req.body.crud = 'select';//select, insert, update, delete 중에 입력
        req.body.mapper_id = 'selectSessionLoginCheck';
    
        router.use('/', dbconnect_Module);
        next('route')
        
      } catch (error) {
        console.log("Module > dbconnect error : "+ error);      
      }
    }
  });
  
  module.exports = router;

5) 노드경로 C:\react200\models에  UserMapper.xml 파일을 생성하고 아래 코드를 붙여넣는다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="UserMapper">  
  <insert id="insertUser"> 
    INSERT INTO react.react_user
    (
      username
      , userorg
      , useremail
      , userpassword
      , usermajor
      , userphone
      , userflag
      , reg_date
      , reg_user
      , update_date
      , update_user
    )
    VALUES (
      #{is_Username}
      , #{is_Organization}
      , CONCAT(#{is_Useremail1}, '@', #{is_Useremail2})
      , #{is_Password}
      , #{is_Usermajor}
      , CONCAT(#{is_Userphone1}, '-', #{is_Userphone2},'-', #{is_Userphone3})
      , 'Y'
      , DATE_FORMAT(now(), '%Y%m%d%H%i%s')
      , CONCAT(#{is_Useremail1}, '@', #{is_Useremail2})
      , DATE_FORMAT(now(), '%Y%m%d%H%i%s')
      , CONCAT(#{is_Useremail1}, '@', #{is_Useremail2})
      )
  </insert>

  <select id="selectUserDpliCheck">
      SELECT 
        count(*) as num
      FROM
      react.react_user
      WHERE useremail = #{is_Email}
  </select>
  
  <select id="selectLoginCheck">
      SELECT 
      username
      , userorg
      , useremail
      , userpassword
      , usermajor
      , userphone
      , userflag
      FROM
      react.react_user
      WHERE useremail = #{is_Email}
  </select>

  <select id="selectSessionLoginCheck">
      SELECT 
      username
      , userorg
      , useremail
      , userpassword
      , usermajor
      , userphone
      , userflag
      FROM
      react.react_user
      WHERE useremail = #{is_Email}
      AND userpassword = #{is_Token}
  </select>
</mapper>

6) C:\react\dbconnect_Module.js에 bcrypt패키지 사용부분을 추가한다. mapper id가 selectLoginCheck인 경우, 로그인 비밀번호와 db에 저장된 회원비밀번호를 bcrypt함수를 사용해 비교한다.

var express = require("express");
var router = express.Router();
const mysql = require("mysql");
const bodyParser = require("body-parser");
const bcrypt = require('bcrypt');

router.use(bodyParser.json());
router.use(bodyParser.urlencoded({ extended: true }));

// Connection Pool 세팅
const pool  = mysql.createPool({
  connectionLimit: 66,
  waitForConnections: true,
  host: "react200.#######.ap-northeast-2.rds.amazonaws.com",
  port: "3306",
  database: 'react',
  user: "admin",
  password: "react200RDS",
});

router.post("/", (req, res) => {
  const mybatisMapper = require("mybatis-mapper");
  var param = req.body;

  //mybatis mapper경로 설정
  mybatisMapper.createMapper(['./models/'+param.mapper+'.xml']);
  var time = new Date();
  console.log('## '+time+ ' ##');
  console.log("\n Called Mapper Name  = "+param.mapper);

  var format = { language: 'sql', indent: '  ' };
  //mysql 쿼리 정보 세팅
  var query = mybatisMapper.getStatement(param.mapper, param.mapper_id, param, format);
  console.log("\n========= Node Mybatis Query Log Start =========");
  console.log("* mapper namespce : "+param.mapper+"."+param.mapper_id+" *\n");
  console.log(query+"\n");
  try {
    pool.getConnection(function(err,connection){
      connection.query(query, function (error, results) {
        if (error) {
          console.log("db error************* : "+error);
        }
        var time2 = new Date();
        console.log('## '+time2+ ' ##');
        console.log('## RESULT DATA LIST ## : \n', results);
        if(results != undefined){
          string = JSON.stringify(results);
          var json = JSON.parse(string);
          if (req.body.crud == "select") {
            if (param.mapper_id == "selectLoginCheck") {
              if (json[0] == undefined) {
                res.send(null);
              } else {
                bcrypt.compare(req.body.is_Password, json[0].userpassword, function(
                  err,
                  login_flag
                ) {
                  if (login_flag == true) {
                    res.send({ json });
                  } else {
                    res.send(null);
                  }
                });
              }
            } else {
              res.send({ json });
            }
          }else{
            res.send("succ");
          }
        }else{
          res.send("error");
        }
  
        connection.release();
        console.log("========= Node Mybatis Query Log End =========\n");
      });
    })
  } catch (error) {
    console.log("pool error : "+error);
  }
});

module.exports = router;

6) 로그인 완료 후, 크롬 개발자도구 > Application탭 > Storage > Cookies > http://localhost:300 순서로 클릭하면, 다음과 같이 쿠키에 jwt로 인코딩 + 암호화 처리된 회원정보가 세팅된 것을 확인할 수 있다.

https://taling.me/Talent/Detail/19341

 

[비전공자도 가능한 웹 프로젝트] 개발부터 배포까지, 배우면서 완성(react,nodejs,mysql,aws)! | 탈잉

✔ 수업 목표 & 5주 뒤 결과물 만들고 싶은 서비스를 직접 구현하게 됩니다. 사람들이 방문하고 액션을 할 수 있는 웹 페이지를 제작 & 배포하는 것까지 진행됩니다. 여러분이 개발 경험이 있든 ��

taling.me:443

강의 문의 : ljung5@naver.com

Comments