-- 벡엔드
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});
// 파일명 : 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>© 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});
}
}
}