Mingyu

Database Change to MongoDB

......@@ -17,6 +17,10 @@ var router = express.Router();
var cookieParser = require('cookie-parser')
var ExpressSession = require('express-session')
var database = require('./database/database');
var config = require('./config');
// get port
var port = process.env.PORT || 3000;
app.set('port',port);
......@@ -64,9 +68,25 @@ app.use(expressErrorHandler.httpError(404));
app.use(errorHandler);
// 프로세스 종료 시에 데이터베이스 연결 해제
process.on('SIGTERM', function () {
console.log("프로세스가 종료됩니다.");
app.close();
});
app.on('close', function () {
console.log("Express 서버 객체가 종료됩니다.");
if (database.db) {
database.db.close();
}
});
// for server listening
var server = http.createServer(app)
server.listen(port,function(){
console.log('익스프레스 서버를 시작했습니다.');
database.init(app, config);
})
......
module.exports = {
server_port: 3000,
db_url: 'mongodb://oss:12341234@cluster0.us5lm.mongodb.net/?retryWrites=true&w=majority',
db_schemas: [
{file:'./user_schema', collection:'users3', schemaName:'UserSchema', modelName:'UserModel'}
]
}
\ No newline at end of file
const mysql = require('mysql')
var pool = mysql.createPool({
host: "localhost",
user: "root",
password: "1234",
port: 3306,
database: "rest_stop"
})
var adduser = function(name, id, password, callback) {
console.log('addUser');
pool.getConnection(function(err, conn) {
if(err){
if(conn){
conn.release();
}
callback(err, null);
return;
}
var data = {name:name, id:id, password:password};
var exec = conn.query('insert into users set ?', data, function(err, result) {
conn.release();
if(err){
console.log('SQL 실행 시 오류 발생');
console.dir(err);
callback(err,null);
return;
}
callback(null, result);
})
})
}
var authUser = function(id, password, callback) {
console.log('authUser 호출');
pool.getConnection(function(err, conn) {
if(err){
if(conn){
conn.release();
}
callback(err, null);
return;
}
var colums = ['name', 'id'];
var tablename = 'users';
var exec = conn.query("select ?? from ?? where id = ? and password = ?",
[colums, tablename, id, password], function(err, rows) {
conn.release();
if(rows.length >0){
console.log('Id [%s], password [$s] 일치하는 사용자 찾음', id, password);
callback(null, rows);
} else {
console.log('일치하는 사용자 없음');
callback(null, null);
}
}
);
})
}
module.exports.pool = pool;
module.exports.authUser = authUser;
module.exports.adduser = adduser;
//module.exports.listuser = listuser;
const Connection = require('./Connection')
var adduser = async (username,userId,userPassword) => {
try {
const query = `INSERT INTO ` +
`accounts ` +
`VALUES ` +
`(null, '$(username)', '$(userId)', '$(userPassword)')`
await Connection(query)
return true;
} catch (error) {
return false;
}
};
var login;
var listuser = function(req, res) {
console.log('user(user2.js) 모듈 안에 있는 listuser 호출됨.');
// 데이터베이스 객체 참조
var database = req.app.get('database');
// 데이터베이스 객체가 초기화된 경우, 모델 객체의 findAll 메소드 호출
if (database.db) {
// 1. 모든 사용자 검색
database.UserModel.findAll(function(err, results) {
// 에러 발생 시, 클라이언트로 에러 전송
if (err) {
console.error('사용자 리스트 조회 중 에러 발생 : ' + err.stack);
res.writeHead('200', {'Content-Type':'text/html;charset=utf8'});
res.write('<h2>사용자 리스트 조회 중 에러 발생</h2>');
res.write('<p>' + err.stack + '</p>');
res.end();
return;
}
if (results) {
console.dir(results);
res.writeHead('200', {'Content-Type':'text/html;charset=utf8'});
res.write('<h2>사용자 리스트</h2>');
res.write('<div><ul>');
for (var i = 0; i < results.length; i++) {
var curId = results[i]._doc.id;
var curName = results[i]._doc.name;
res.write(' <li>#' + i + ' : ' + curId + ', ' + curName + '</li>');
}
res.write('</ul></div>');
res.end();
} else {
res.writeHead('200', {'Content-Type':'text/html;charset=utf8'});
res.write('<h2>사용자 리스트 조회 실패</h2>');
res.end();
}
});
} else {
res.writeHead('200', {'Content-Type':'text/html;charset=utf8'});
res.write('<h2>데이터베이스 연결 실패</h2>');
res.end();
}
};
//사용자를 인증하는 함수 : 아이디로 먼저 찾고 비밀번호를 그 다음에 비교하도록 함
var authUser = function(database, id, password, callback) {
console.log('authUser 호출됨.');
// 1. 아이디를 이용해 검색
database.UserModel.findById(id, function(err, results) {
if (err) {
callback(err, null);
return;
}
console.log('아이디 [%s]로 사용자 검색결과', id);
console.dir(results);
if (results.length > 0) {
console.log('아이디와 일치하는 사용자 찾음.');
// 2. 패스워드 확인 : 모델 인스턴스를 객체를 만들고 authenticate() 메소드 호출
var user = new database.UserModel({id:id});
var authenticated = user.authenticate(password, results[0]._doc.salt, results[0]._doc.hashed_password);
if (authenticated) {
console.log('비밀번호 일치함');
callback(null, results);
} else {
console.log('비밀번호 일치하지 않음');
callback(null, null);
}
} else {
console.log("아이디와 일치하는 사용자를 찾지 못함.");
callback(null, null);
}
});
}
//사용자를 등록하는 함수
var addUser = function(database, id, password, name, callback) {
console.log('addUser 호출됨.');
// UserModel 인스턴스 생성
var user = new database.UserModel({"id":id, "password":password, "name":name});
// save()로 저장
user.save(function(err) {
if (err) {
callback(err, null);
return;
}
console.log("사용자 데이터 추가함.");
callback(null, user);
});
}
module.exports.login = login;
module.exports.adduser = adduser;
module.exports.listuser = listuser;
var mongoose = require('mongoose');
var db_url = 'mongodb+srv://oss:12341234@cluster0.us5lm.mongodb.net/?retryWrites=true&w=majority';
// database 객체에 db, schema, model 모두 추가
var database = {};
// 초기화를 위해 호출하는 함수
database.init = function(app, config) {
console.log('init() 호출됨.');
connect(app, config);
}
//데이터베이스에 연결하고 응답 객체의 속성으로 db 객체 추가
function connect(app, config) {
console.log('connect() 호출됨.');
// 데이터베이스 연결 : config의 설정 사용
mongoose.Promise = global.Promise; // mongoose의 Promise 객체는 global의 Promise 객체 사용하도록 함
mongoose.connect(db_url);
database.db = mongoose.connection;
database.db.on('error', console.error.bind(console, 'mongoose connection error.'));
database.db.on('open', function () {
console.log('데이터베이스에 연결되었습니다. : ' + db_url);
// config에 등록된 스키마 및 모델 객체 생성
createSchema(app, config);
});
database.db.on('disconnected', connect);
}
// config에 정의된 스키마 및 모델 객체 생성
function createSchema(app, config) {
var schemaLen = config.db_schemas.length;
console.log('설정에 정의된 스키마의 수 : %d', schemaLen);
for (var i = 0; i < schemaLen; i++) {
var curItem = config.db_schemas[i];
// 모듈 파일에서 모듈 불러온 후 createSchema() 함수 호출하기
var curSchema = require(curItem.file).createSchema(mongoose);
console.log('%s 모듈을 불러들인 후 스키마 정의함.', curItem.file);
// User 모델 정의
var curModel = mongoose.model(curItem.collection, curSchema);
console.log('%s 컬렉션을 위해 모델 정의함.', curItem.collection);
// database 객체에 속성으로 추가
database[curItem.schemaName] = curSchema;
database[curItem.modelName] = curModel;
console.log('스키마 이름 [%s], 모델 이름 [%s] 이 database 객체의 속성으로 추가됨.', curItem.schemaName, curItem.modelName);
}
app.set('database', database);
console.log('database 객체가 app 객체의 속성으로 추가됨.');
}
// database 객체를 module.exports에 할당
module.exports = database;
\ No newline at end of file
var crypto = require('crypto');
var Schema = {};
Schema.createSchema = function(mongoose) {
// 스키마 정의
var UserSchema = mongoose.Schema({
id: {type: String, required: true, unique: true, 'default':''},
hashed_password: {type: String, required: true, 'default':''},
salt: {type:String, required:true},
name: {type: String, index: 'hashed', 'default':''},
age: {type: Number, 'default': -1},
created_at: {type: Date, index: {unique: false}, 'default': Date.now},
updated_at: {type: Date, index: {unique: false}, 'default': Date.now}
});
// password를 virtual 메소드로 정의 : MongoDB에 저장되지 않는 편리한 속성임. 특정 속성을 지정하고 set, get 메소드를 정의함
UserSchema
.virtual('password')
.set(function(password) {
this._password = password;
this.salt = this.makeSalt();
this.hashed_password = this.encryptPassword(password);
console.log('virtual password 호출됨 : ' + this.hashed_password);
})
.get(function() { return this._password });
// 스키마에 모델 인스턴스에서 사용할 수 있는 메소드 추가
// 비밀번호 암호화 메소드
UserSchema.method('encryptPassword', function(plainText, inSalt) {
if (inSalt) {
return crypto.createHmac('sha1', inSalt).update(plainText).digest('hex');
} else {
return crypto.createHmac('sha1', this.salt).update(plainText).digest('hex');
}
});
// salt 값 만들기 메소드
UserSchema.method('makeSalt', function() {
return Math.round((new Date().valueOf() * Math.random())) + '';
});
// 인증 메소드 - 입력된 비밀번호와 비교 (true/false 리턴)
UserSchema.method('authenticate', function(plainText, inSalt, hashed_password) {
if (inSalt) {
console.log('authenticate 호출됨 : %s -> %s : %s', plainText, this.encryptPassword(plainText, inSalt), hashed_password);
return this.encryptPassword(plainText, inSalt) === hashed_password;
} else {
console.log('authenticate 호출됨 : %s -> %s : %s', plainText, this.encryptPassword(plainText), this.hashed_password);
return this.encryptPassword(plainText) === this.hashed_password;
}
});
// 값이 유효한지 확인하는 함수 정의
var validatePresenceOf = function(value) {
return value && value.length;
};
// 저장 시의 트리거 함수 정의 (password 필드가 유효하지 않으면 에러 발생)
UserSchema.pre('save', function(next) {
if (!this.isNew) return next();
if (!validatePresenceOf(this.password)) {
next(new Error('유효하지 않은 password 필드입니다.'));
} else {
next();
}
})
// 필수 속성에 대한 유효성 확인 (길이값 체크)
UserSchema.path('id').validate(function (id) {
return id.length;
}, 'id 칼럼의 값이 없습니다.');
UserSchema.path('name').validate(function (name) {
return name.length;
}, 'name 칼럼의 값이 없습니다.');
UserSchema.path('hashed_password').validate(function (hashed_password) {
return hashed_password.length;
}, 'hashed_password 칼럼의 값이 없습니다.');
// 스키마에 static 메소드 추가
UserSchema.static('findById', function(id, callback) {
return this.find({id:id}, callback);
});
UserSchema.static('findAll', function(callback) {
return this.find({}, callback);
});
console.log('UserSchema 정의함.');
return UserSchema;
};
// module.exports에 UserSchema 객체 직접 할당
module.exports = Schema;
var Conn = require('../database/database')
var express = require('express')
var Conn = require('../database/Connection')
var router = express.Router()
var router = express.Router();
//라우팅 함수 등록
router.get('/',function(req,res){
res.render('login.html')
});
......@@ -15,45 +16,90 @@ router.post('/process', function(req, res) {
var paramPassword = req.body.password || req.query.password;
//GET, POST 모두 고려해서 둘 다 검사
if(Conn.pool){
Conn.authUser(paramId, paramPassword, function(err, rows) {
if(err){
console.error(err.stack);
res.writeHead('200', { 'Content-Type': 'text/html;charset=utf8' });
res.write('<h1>로그인 중 오류</h1>');
res.write('<div><p>Param id : ' + paramId + '</p></div>');
res.write('<div><p>Param password : ' + paramPassword + '</p></div>');
res.write("<br><br><a href ='/login'>로그인 페이지로 돌아가기</a>");
res.end();
return;
// 데이터베이스 객체 참조
var database = req.app.get('database');
// 데이터베이스 객체가 초기화된 경우, authUser 함수 호출하여 사용자 인증
if (database.db) {
authUser(database, paramId, paramPassword, function(err, docs) {
// 에러 발생 시, 클라이언트로 에러 전송
if (err) {
console.error('사용자 로그인 중 에러 발생 : ' + err.stack);
res.writeHead('200', {'Content-Type':'text/html;charset=utf8'});
res.write('<h2>사용자 로그인 중 에러 발생</h2>');
res.write('<p>' + err.stack + '</p>');
res.end();
return;
}
if (rows){
console.dir(rows);
res.writeHead('200', { 'Content-Type': 'text/html;charset=utf8' });
res.write('<h1>로그인 성공</h1>');
res.write('<div><p>Param name : ' + rows[0].name + '</p></div>');
res.write('<div><p>Param id : ' + paramId + '</p></div>');
res.write("<br><br><a href ='/login'>로그인 페이지로 돌아가기</a>");
res.end();
} else {
res.writeHead('200', { 'Content-Type': 'text/html;charset=utf8' });
res.write('<h1>로그인 실패.</h1>');
res.write('<div><p>Param id : ' + paramId + '</p></div>');
res.write("<br><br><a href ='/login'>로그인 페이지로 돌아가기</a>");
res.end();
}
})
}else{
res.writeHead('200', { 'Content-Type': 'text/html;charset=utf8' });
res.write('<h1>데이터베이스 연결 실패</h1>');
res.end();
}
// 조회된 레코드가 있으면 성공 응답 전송
if (docs) {
console.dir(docs);
// 조회 결과에서 사용자 이름 확인
var username = docs[0].name;
res.writeHead('200', {'Content-Type':'text/html;charset=utf8'});
res.write('<h1>로그인 성공</h1>');
res.write('<div><p>사용자 아이디 : ' + paramId + '</p></div>');
res.write('<div><p>사용자 이름 : ' + username + '</p></div>');
res.write("<br><br><a href='/login'>다시 로그인하기</a>");
res.end();
} else { // 조회된 레코드가 없는 경우 실패 응답 전송
res.writeHead('200', {'Content-Type':'text/html;charset=utf8'});
res.write('<h1>로그인 실패</h1>');
res.write('<div><p>아이디와 패스워드를 다시 확인하십시오.</p></div>');
res.write("<br><br><a href='/login'>다시 로그인하기</a>");
res.end();
}
});
} else { // 데이터베이스 객체가 초기화되지 않은 경우 실패 응답 전송
res.writeHead('200', {'Content-Type':'text/html;charset=utf8'});
res.write('<h2>데이터베이스 연결 실패</h2>');
res.write('<div><p>데이터베이스에 연결하지 못했습니다.</p></div>');
res.end();
}
});
//사용자를 인증하는 함수 : 아이디로 먼저 찾고 비밀번호를 그 다음에 비교하도록 함
var authUser = function(database, id, password, callback) {
console.log('authUser 호출됨.');
// 1. 아이디를 이용해 검색
database.UserModel.findById(id, function(err, results) {
if (err) {
callback(err, null);
return;
}
console.log('아이디 [%s]로 사용자 검색결과', id);
console.dir(results);
if (results.length > 0) {
console.log('아이디와 일치하는 사용자 찾음.');
// 2. 패스워드 확인 : 모델 인스턴스를 객체를 만들고 authenticate() 메소드 호출
var user = new database.UserModel({id:id});
var authenticated = user.authenticate(password, results[0]._doc.salt, results[0]._doc.hashed_password);
if (authenticated) {
console.log('비밀번호 일치함');
callback(null, results);
} else {
console.log('비밀번호 일치하지 않음');
callback(null, null);
}
} else {
console.log("아이디와 일치하는 사용자를 찾지 못함.");
callback(null, null);
}
});
}
module.exports = router
\ No newline at end of file
......
var express = require('express')
var Conn = require('../database/Connection')
var Conn = require('../database/database')
var router = express.Router()
router.get('/',function(req,res){
......@@ -15,47 +15,66 @@ router.post('/process', function(req, res) {
var paramPassword = req.body.password || req.query.password;
//GET, POST 모두 고려해서 둘 다 검사
if(Conn.pool){
Conn.adduser(paramName, paramId, paramPassword, function(err, addedUser) {
if(err){
console.error(err.stack);
res.writeHead('200', { 'Content-Type': 'text/html;charset=utf8' });
res.write('<h1>ID가 중복되었습니다. 다른 ID를 사용해주세요.</h1>');
res.write('<div><p>Param name : ' + paramName + '</p></div>');
res.write('<div><p>Param id : ' + paramId + '</p></div>');
res.write('<div><p>Param password : ' + paramPassword + '</p></div>');
res.write("<br><br><a href ='/login'>로그인 페이지로 돌아가기</a>");
res.end();
return;
// 데이터베이스 객체 참조
var database = req.app.get('database');
// 데이터베이스 객체가 초기화된 경우, addUser 함수 호출하여 사용자 추가
if (database.db) {
addUser(database, paramId, paramPassword, paramName, function(err, addedUser) {
// 동일한 id로 추가하려는 경우 에러 발생 - 클라이언트로 에러 전송
if (err) {
console.error('사용자 추가 중 에러 발생 : ' + err.stack);
res.writeHead('200', {'Content-Type':'text/html;charset=utf8'});
res.write('<h2>사용자 추가 중 에러 발생</h2>');
res.write('<p>' + err.stack + '</p>');
res.end();
return;
}
if (addedUser){
console.dir(addedUser);
res.writeHead('200', { 'Content-Type': 'text/html;charset=utf8' });
res.write('<h1>회원가입 성공</h1>');
res.write('<div><p>Param name : ' + paramName + '</p></div>');
res.write('<div><p>Param id : ' + paramId + '</p></div>');
res.write('<div><p>Param password : ' + paramPassword + '</p></div>');
res.write("<br><br><a href ='/login'>로그인 페이지로 돌아가기</a>");
res.end();
} else {
res.writeHead('200', { 'Content-Type': 'text/html;charset=utf8' });
res.write('<h1>회원가입 실패.</h1>');
res.write('<div><p>Param id : ' + paramId + '</p></div>');
res.write('<div><p>Param password : ' + paramPassword + '</p></div>');
res.write("<br><br><a href ='/login'>로그인 페이지로 돌아가기</a>");
res.end();
}
})
}else{
res.writeHead('200', { 'Content-Type': 'text/html;charset=utf8' });
res.write('<h1>데이터베이스 연결 실패</h1>');
res.end();
}
// 결과 객체 있으면 성공 응답 전송
if (addedUser) {
console.dir(addedUser);
res.writeHead('200', {'Content-Type':'text/html;charset=utf8'});
res.write('<h2>사용자 추가 성공</h2>');
res.write("<br><br><a href='/login'>다시 로그인하기</a>");
res.end();
} else { // 결과 객체가 없으면 실패 응답 전송
res.writeHead('200', {'Content-Type':'text/html;charset=utf8'});
res.write('<h2>사용자 추가 실패</h2>');
res.write("<br><br><a href='/signup'>다시 가입하기</a>");
res.end();
}
});
} else { // 데이터베이스 객체가 초기화되지 않은 경우 실패 응답 전송
res.writeHead('200', {'Content-Type':'text/html;charset=utf8'});
res.write('<h2>데이터베이스 연결 실패</h2>');
res.end();
}
});
});
//사용자를 등록하는 함수
var addUser = function(database, id, password, name, callback) {
console.log('addUser 호출됨.');
// UserModel 인스턴스 생성
var user = new database.UserModel({"id":id, "password":password, "name":name});
// save()로 저장
user.save(function(err) {
if (err) {
callback(err, null);
return;
}
console.log("사용자 데이터 추가함.");
callback(null, user);
});
}
module.exports = router
\ No newline at end of file
......
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
......@@ -12,11 +12,13 @@
"body-parser": "^1.20.0",
"bootstrap": "^5.1.3",
"cookie-parser": "^1.4.6",
"crypto": "^1.0.1",
"ejs": "^3.1.7",
"express": "^4.18.1",
"express-error-handler": "^1.1.0",
"express-session": "^1.17.3",
"http": "^0.0.1-security",
"mongoose": "^6.3.4",
"mysql": "^2.18.1",
"path": "^0.12.7",
"serve-static": "^1.15.0"
......