-- 벡엔드
CMD> nodemon --inspect ./bin/www

-- 프론트엔드
CMD> npm run serve


//조회 : await this.axios.get(url, {headers:headers});
//추가 : await this.axios.post(url, body, {headers:headers});
//수정 : await this.axios.put(url, body, {headers:headers});

//삭제 : await this.axios.delete(url, {headers:headers, data:{}});

// 파일명 : Join.vue

<div>
    <el-card shadow="always">

        <h3>회원가입</h3>

        {{ member }}

        <el-form :inline="true" class="demo-form-inline" style="margin-bottom:-20px">
            <el-form-item label="아이디" label-width="120px">
                <el-input v-model="member.uid" size="mini" placeholder="아이디"></el-input>
            </el-form-item>
            <el-form-item >
                <el-button size="mini" @click="handleIDCheck">중복확인</el-button>
            </el-form-item>
        </el-form>
        

        <el-form :inline="true" class="demo-form-inline" style="margin-bottom:-20px">
            <el-form-item label="암호" label-width="120px">
                <el-input v-model="member.upw" size="mini" placeholder="암호" show-password></el-input>
            </el-form-item>
        </el-form>

        <el-form :inline="true" class="demo-form-inline" style="margin-bottom:-20px">
            <el-form-item label="암호확인" label-width="120px">
                <el-input v-model="member.userpw1" size="mini" placeholder="암호확인" show-password></el-input>
            </el-form-item>
        </el-form>

        <el-form :inline="true" class="demo-form-inline" style="margin-bottom:-20px">
            <el-form-item label="나이" label-width="120px">
                <el-input v-model="member.uage" type="number" size="mini" placeholder="나이"></el-input>
            </el-form-item>
        </el-form>

        <el-form :inline="true" class="demo-form-inline" style="margin-bottom:-20px">
            <el-form-item  label="생년월일" label-width="120px">             
                <el-date-picker v-model="member.ubirth" type="date"  size="mini"  placeholder="날짜를 선택 하세요" style="width: 100%"></el-date-picker>            
            </el-form-item>
        </el-form>

        <el-form :inline="true" class="demo-form-inline" style="margin-bottom:-20px">
            <el-form-item label="이메일" label-width="120px">
                <el-input v-model="member.useremail" size="mini" placeholder="이메일"></el-input>
            </el-form-item>
            <el-form-item >@</el-form-item>
            <el-form-item >
                <el-select v-model="member.useremail1" size="mini" placeholder="선택">
                    <el-option v-for="tmp in emailoption" :key="tmp"
                        :label="tmp" :value="tmp"></el-option>
                </el-select>
            </el-form-item>        
        </el-form>

        <el-form :inline="true" class="demo-form-inline" style="margin-bottom:-20px">
            <el-form-item label="관심분야" label-width="120px">
                <el-checkbox-group v-model="member.ucheck">
                    <el-checkbox v-for="tmp in typeoption" :key="tmp" :label="tmp"></el-checkbox>
                </el-checkbox-group>
            </el-form-item>
        </el-form>

        <el-form :inline="true" class="demo-form-inline" style="margin-bottom:-20px">
            <el-form-item label="성별" label-width="120px">
                <el-radio-group v-model="member.ugender">
                    <el-radio label="1">남자</el-radio>
                    <el-radio label="2">여자</el-radio>
                </el-radio-group>
            </el-form-item>
        </el-form>

        <el-form :inline="true" class="demo-form-inline" style="margin-bottom:-20px">
            <el-form-item label="약관내용" label-width="120px">
                <el-input v-model="member.text" type="textarea" resize="none"></el-input>
            </el-form-item>
        </el-form>
        
        <el-form :inline="true" class="demo-form-inline" style="margin-bottom:-20px">
            <el-form-item label=" " label-width="120px">
                <el-checkbox v-model="member.chk" label="약관동의"></el-checkbox>
            </el-form-item>
        </el-form>

        <el-form :inline="true" class="demo-form-inline" style="margin-bottom:-20px">
            <el-form-item label=" " label-width="120px">
                <el-button type="primary" size="mini" @click="handleJoin">회원가입</el-button>
                <el-button size="mini"></el-button>
            </el-form-item>
        </el-form>
    </el-card>

</div>


// 파일명 : Login.vue

<div>
    <el-card shadow="always">

        <h3>로그인</h3>
        {{ member }}

        <el-form :inline="true" class="demo-form-inline" style="margin-bottom:-20px">
            <el-form-item label="아이디" label-width="120px">
                <el-input v-model="member.uid" size="mini" placeholder="아이디" style="width:192px"></el-input>
            </el-form-item>
        </el-form>

        <el-form :inline="true" class="demo-form-inline" style="margin-bottom:-20px">
            <el-form-item label="암호" label-width="120px">
                <el-input v-model="member.upw" size="mini" placeholder="암호" show-password></el-input>
            </el-form-item>
        </el-form>


        <el-form :inline="true" class="demo-form-inline" style="margin-bottom:-20px">
            <el-form-item label=" " label-width="120px">
                <el-button type="primary" size="mini" @click="handleLogin">로그인</el-button>
                
                <el-button size="mini" @click="handleHome"></el-button>

            </el-form-item>
        </el-form>
    </el-card>

</div>


// 파일명 : App.vue

<el-container>
  <el-header>
    <el-menu class="el-menu-demo" mode="horizontal" :router="true">
      <el-menu-item index="home" ref="home"></el-menu-item>

      <el-menu-item index="login" ref="login" v-show="!logged">로그인</el-menu-item>
      <el-menu-item index="join" ref="join" v-show="!logged">회원가입</el-menu-item>

      <el-menu-item index="logout" ref="logout" v-show="logged">로그아웃</el-menu-item>
      <el-menu-item index="mypage" ref="mypage" v-show="logged">마이페이지</el-menu-item>
      
      <el-menu-item index="board" ref="board">게시판</el-menu-item>
      <el-menu-item index="seller" ref="seller">판매자</el-menu-item>
    </el-menu>
  </el-header>
  <!-- v-if= 태그를 생성시키지 않음  -->
  <!-- v-show= 태그 생성, 숨김으로  -->

  <el-main>
    <router-view></router-view>
  </el-main>
 
  <el-footer>&copy; vue project</el-footer>
</el-container>

======================================
//파일명 : routes/member.js
var express = require('express');
var router = express.Router();

// 몽고DB연동
// CMD> npm i mongodb --save
const db = require('mongodb').MongoClient;
const DBURL = require('../config/db').mongodbURL;
const DBNAME = require('../config/db').mongodbDB;

// 로그인시에 토큰발행
// CMD> npm i jsonwebtoken --save
const jwt = require('jsonwebtoken');
const jwtKey = require('../config/auth').securityKey;
const jwtOptions = require('../config/auth').options;
const checkToken = require('../config/auth').checkToken;

// 회원가입, 로그인시 암호 hash용
const crypto = require('crypto');

// 회원정보수정 : http://localhost:3000/member/mypage?menu=1
// 비밀번호변경 : http://localhost:3000/member/mypage?menu=2
// 회원탈퇴 : http://localhost:3000/member/mypage?menu=3
router.put('/mypage', checkToken, async function(req, res, next) {
try {
console.log("2. member.js => ", req.body);
return res.send({status:200});
}
catch(err) {
console.error(err);
return res.send({status:-1, result : err});
}
});

// 로그인 : http://localhost:3000/member/select
// 암호정보가 있어서 post
router.post('/select', async function(req, res, next) {
try {
// 회원가입시 사용했던 암호화 방식으로 hash해야
// DB에서 로그인 비교가 가능함.
const hash = crypto.createHmac('sha256', req.body.uid)
.update(req.body.upw).digest('hex');

    const obj = {
        userid : req.body.uid,
        userpw : hash
    };

    console.log(obj);

    const dbConn   = await db.connect(DBURL);
    const coll     = dbConn.db(DBNAME).collection("member");

    // const query = { $and : [{_id:obj.userid}, {userpw:obj.userpw}] };
    const query    = { _id:obj.userid, userpw:obj.userpw };
    const result   = await coll.findOne(query);

    console.log(result);  // 실패 or 성공
    if(result !== null){ // DB에 일치하는 경우 
        const token = {
            token : jwt.sign( 
                { uid:result._id },     // 토큰에 포함할 내용들...
                jwtKey,                 // 토큰생성 키 
                jwtOptions              // 옵션
            ),
            refreshToken : null,        // null
        }
        return res.send({status:200, result : token});    
    }

    // 일치하지 않을 경우
    return res.send({status:0});
}
catch(err) {
    console.error(err);
    return res.send({status:-1, result : err});
} 

});

// 회원가입 : http://localhost:3000/member/insert
router.post('/insert', async function(req, res, next) {
try{
console.log(req.body);
// hash(salt)는 abc -> io3rj987io23873987437839ufj3983r
const hash = crypto.createHmac('sha256', req.body.uid)
.update(req.body.upw).digest('hex');
const obj = {
_id : req.body.uid,
userpw : hash,
userage : Number(req.body.uage),
userbirth : req.body.ubirth,
useremail : req.body.uemail,
usercheck : req.body.ucheck,
usergender : Number(req.body.ugender)
};
console.log(obj);

    const dbConn   = await db.connect(DBURL);
    const coll     = dbConn.db(DBNAME).collection("member");

    const result = await coll.insertOne(obj); //{ }
    console.log(result); // 성공 or 실패
    if( result.insertedId === obj._id ) {
        return res.send({status:200});
    }
    return res.send({status:0});
}
catch(err) {
    console.error(err);
    return res.send({status:-1, result : err});
} 

});

// 아이디중복확인 : http://localhost:3000/member/idcheck?uid=aa
router.get('/idcheck', async function(req, res, next) {
try {
const userid = req.query.uid;

    const dbConn   = await db.connect(DBURL);
    const coll     = dbConn.db(DBNAME).collection("member");

    const query    = { _id : userid };
    const result   = await coll.countDocuments(query);

    console.log(result); //{  }
    return res.send({status:200, result:result});
}
catch(err) {
    console.error(err);
    return res.send({status:-1, result : err});
} 

});

module.exports = router;


// 파일명 : config/auth.js

// 토큰생성, 추출, 검증에 필요함
const jwt = require('jsonwebtoken');

var self = module.exports = {
securityKey : 'fjifej$%e_ijfj39890uu94343',
options : {
algorithm : 'HS256', // 토큰 생성 hash알고리즘
expiresIn : '9h', // 토큰만료시간 ex) 9시간
issuer : 'corp01', // 토큰 발행자
},

// 토큰이 전달되면 토큰의 유효성을 검증함.
checkToken : async(req, res, next) => {
    try {
        const token = req.headers.token;
        // 1. 토큰이 있느냐?
        if(!token){
            return res.send({status:888, result:'유효하지않는 토큰'});
        }
        // 2. 토큰 decode 추출(토큰과 암호키)
        const user = jwt.verify(token, self.securityKey);
        if(typeof user.uid === 'undefined'){
            return res.send({status:888, result:'유효하지않는 토큰'});
        }

        console.log('토큰에서 추출한 아이디 => ', user.uid);
        req.body.userid = user.uid;

        // 위쪽에서 토큰에 대한 유효성을 모두 pass할경우 다음으로 넘김
        next();
    }
    catch(err){
        console.error(err);
        return res.send({status:-1, result : err});
    }
}

}

0개의 댓글