min1925k@gmail.com

Merge 'database'

# Conflicts:
#	app/routes/signup.js
1 +node_modules
...\ No newline at end of file ...\ No newline at end of file
...@@ -15,6 +15,12 @@ var csvRouter = require('./routes/csv') ...@@ -15,6 +15,12 @@ var csvRouter = require('./routes/csv')
15 var app = express(); 15 var app = express();
16 var router = express.Router(); 16 var router = express.Router();
17 17
18 +var cookieParser = require('cookie-parser')
19 +var ExpressSession = require('express-session')
20 +
21 +var database = require('./database/database');
22 +var config = require('./config');
23 +
18 24
19 // get port 25 // get port
20 var port = process.env.PORT || 3000; 26 var port = process.env.PORT || 3000;
...@@ -46,6 +52,13 @@ app.use('/signup',signupRouter); // sign up page route ...@@ -46,6 +52,13 @@ app.use('/signup',signupRouter); // sign up page route
46 app.use('/', indexRouter); // main page route 52 app.use('/', indexRouter); // main page route
47 53
48 54
55 +//Session 처리
56 +app.use(cookieParser());
57 +app.use(ExpressSession({
58 + secret:'key',
59 + resave: true,
60 + saveUninitialized:true
61 +}));
49 62
50 //모든 router 처리가 끝난 후 404 오류 페이지 처리 63 //모든 router 처리가 끝난 후 404 오류 페이지 처리
51 var errorHandler = expressErrorHandler({ 64 var errorHandler = expressErrorHandler({
...@@ -57,9 +70,25 @@ app.use(expressErrorHandler.httpError(404)); ...@@ -57,9 +70,25 @@ app.use(expressErrorHandler.httpError(404));
57 app.use(errorHandler); 70 app.use(errorHandler);
58 71
59 72
73 +// 프로세스 종료 시에 데이터베이스 연결 해제
74 +process.on('SIGTERM', function () {
75 + console.log("프로세스가 종료됩니다.");
76 + app.close();
77 +});
78 +
79 +app.on('close', function () {
80 + console.log("Express 서버 객체가 종료됩니다.");
81 + if (database.db) {
82 + database.db.close();
83 + }
84 +});
85 +
60 86
61 // for server listening 87 // for server listening
62 var server = http.createServer(app) 88 var server = http.createServer(app)
63 server.listen(port,function(){ 89 server.listen(port,function(){
64 console.log('익스프레스 서버를 시작했습니다.'); 90 console.log('익스프레스 서버를 시작했습니다.');
91 +
92 + database.init(app, config);
65 }) 93 })
94 +
......
1 +module.exports = {
2 + server_port: 3000,
3 + db_url: 'mongodb://oss:12341234@cluster0.us5lm.mongodb.net/?retryWrites=true&w=majority',
4 + db_schemas: [
5 + {file:'./user_schema', collection:'users3', schemaName:'UserSchema', modelName:'UserModel'}
6 + ]
7 +}
...\ No newline at end of file ...\ No newline at end of file
1 +var mongoose = require('mongoose');
2 +var db_url = 'mongodb+srv://oss:12341234@cluster0.us5lm.mongodb.net/?retryWrites=true&w=majority';
3 +// database 객체에 db, schema, model 모두 추가
4 +var database = {};
5 +
6 +// 초기화를 위해 호출하는 함수
7 +database.init = function(app, config) {
8 + console.log('init() 호출됨.');
9 +
10 + connect(app, config);
11 +}
12 +
13 +//데이터베이스에 연결하고 응답 객체의 속성으로 db 객체 추가
14 +function connect(app, config) {
15 + console.log('connect() 호출됨.');
16 +
17 + // 데이터베이스 연결 : config의 설정 사용
18 + mongoose.Promise = global.Promise; // mongoose의 Promise 객체는 global의 Promise 객체 사용하도록 함
19 + mongoose.connect(db_url);
20 +
21 + database.db = mongoose.connection;
22 +
23 + database.db.on('error', console.error.bind(console, 'mongoose connection error.'));
24 + database.db.on('open', function () {
25 + console.log('데이터베이스에 연결되었습니다. : ' + db_url);
26 +
27 + // config에 등록된 스키마 및 모델 객체 생성
28 + createSchema(app, config);
29 +
30 + });
31 + database.db.on('disconnected', connect);
32 +
33 +}
34 +
35 +// config에 정의된 스키마 및 모델 객체 생성
36 +function createSchema(app, config) {
37 + var schemaLen = config.db_schemas.length;
38 + console.log('설정에 정의된 스키마의 수 : %d', schemaLen);
39 +
40 + for (var i = 0; i < schemaLen; i++) {
41 + var curItem = config.db_schemas[i];
42 +
43 + // 모듈 파일에서 모듈 불러온 후 createSchema() 함수 호출하기
44 + var curSchema = require(curItem.file).createSchema(mongoose);
45 + console.log('%s 모듈을 불러들인 후 스키마 정의함.', curItem.file);
46 +
47 + // User 모델 정의
48 + var curModel = mongoose.model(curItem.collection, curSchema);
49 + console.log('%s 컬렉션을 위해 모델 정의함.', curItem.collection);
50 +
51 + // database 객체에 속성으로 추가
52 + database[curItem.schemaName] = curSchema;
53 + database[curItem.modelName] = curModel;
54 + console.log('스키마 이름 [%s], 모델 이름 [%s] 이 database 객체의 속성으로 추가됨.', curItem.schemaName, curItem.modelName);
55 + }
56 +
57 + app.set('database', database);
58 + console.log('database 객체가 app 객체의 속성으로 추가됨.');
59 +}
60 +
61 +
62 +// database 객체를 module.exports에 할당
63 +module.exports = database;
...\ No newline at end of file ...\ No newline at end of file
1 +var crypto = require('crypto');
2 +
3 +var Schema = {};
4 +
5 +Schema.createSchema = function(mongoose) {
6 +
7 + // 스키마 정의
8 + var UserSchema = mongoose.Schema({
9 + id: {type: String, required: true, unique: true, 'default':''},
10 + hashed_password: {type: String, required: true, 'default':''},
11 + salt: {type:String, required:true},
12 + name: {type: String, index: 'hashed', 'default':''},
13 + age: {type: Number, 'default': -1},
14 + created_at: {type: Date, index: {unique: false}, 'default': Date.now},
15 + updated_at: {type: Date, index: {unique: false}, 'default': Date.now}
16 + });
17 +
18 + // password를 virtual 메소드로 정의 : MongoDB에 저장되지 않는 편리한 속성임. 특정 속성을 지정하고 set, get 메소드를 정의함
19 + UserSchema
20 + .virtual('password')
21 + .set(function(password) {
22 + this._password = password;
23 + this.salt = this.makeSalt();
24 + this.hashed_password = this.encryptPassword(password);
25 + console.log('virtual password 호출됨 : ' + this.hashed_password);
26 + })
27 + .get(function() { return this._password });
28 +
29 + // 스키마에 모델 인스턴스에서 사용할 수 있는 메소드 추가
30 + // 비밀번호 암호화 메소드
31 + UserSchema.method('encryptPassword', function(plainText, inSalt) {
32 + if (inSalt) {
33 + return crypto.createHmac('sha1', inSalt).update(plainText).digest('hex');
34 + } else {
35 + return crypto.createHmac('sha1', this.salt).update(plainText).digest('hex');
36 + }
37 + });
38 +
39 + // salt 값 만들기 메소드
40 + UserSchema.method('makeSalt', function() {
41 + return Math.round((new Date().valueOf() * Math.random())) + '';
42 + });
43 +
44 + // 인증 메소드 - 입력된 비밀번호와 비교 (true/false 리턴)
45 + UserSchema.method('authenticate', function(plainText, inSalt, hashed_password) {
46 + if (inSalt) {
47 + console.log('authenticate 호출됨 : %s -> %s : %s', plainText, this.encryptPassword(plainText, inSalt), hashed_password);
48 + return this.encryptPassword(plainText, inSalt) === hashed_password;
49 + } else {
50 + console.log('authenticate 호출됨 : %s -> %s : %s', plainText, this.encryptPassword(plainText), this.hashed_password);
51 + return this.encryptPassword(plainText) === this.hashed_password;
52 + }
53 + });
54 +
55 + // 값이 유효한지 확인하는 함수 정의
56 + var validatePresenceOf = function(value) {
57 + return value && value.length;
58 + };
59 +
60 + // 저장 시의 트리거 함수 정의 (password 필드가 유효하지 않으면 에러 발생)
61 + UserSchema.pre('save', function(next) {
62 + if (!this.isNew) return next();
63 +
64 + if (!validatePresenceOf(this.password)) {
65 + next(new Error('유효하지 않은 password 필드입니다.'));
66 + } else {
67 + next();
68 + }
69 + })
70 +
71 + // 필수 속성에 대한 유효성 확인 (길이값 체크)
72 + UserSchema.path('id').validate(function (id) {
73 + return id.length;
74 + }, 'id 칼럼의 값이 없습니다.');
75 +
76 + UserSchema.path('name').validate(function (name) {
77 + return name.length;
78 + }, 'name 칼럼의 값이 없습니다.');
79 +
80 + UserSchema.path('hashed_password').validate(function (hashed_password) {
81 + return hashed_password.length;
82 + }, 'hashed_password 칼럼의 값이 없습니다.');
83 +
84 +
85 + // 스키마에 static 메소드 추가
86 + UserSchema.static('findById', function(id, callback) {
87 + return this.find({id:id}, callback);
88 + });
89 +
90 + UserSchema.static('findAll', function(callback) {
91 + return this.find({}, callback);
92 + });
93 +
94 + console.log('UserSchema 정의함.');
95 +
96 + return UserSchema;
97 +};
98 +
99 +// module.exports에 UserSchema 객체 직접 할당
100 +module.exports = Schema;
101 +
1 +var Conn = require('../database/database')
1 var express = require('express') 2 var express = require('express')
2 -var router = express.Router() 3 +var router = express.Router();
3 4
4 //라우팅 함수 등록 5 //라우팅 함수 등록
5 6
6 router.get('/',function(req,res){ 7 router.get('/',function(req,res){
8 +
7 res.render('login.html') 9 res.render('login.html')
8 }); 10 });
9 11
10 router.post('/process', function(req, res) { 12 router.post('/process', function(req, res) {
11 - console.log('/process/login 처리함'); 13 + console.log('/login/process 처리함');
12 14
13 var paramId = req.body.id || req.query.id; 15 var paramId = req.body.id || req.query.id;
14 var paramPassword = req.body.password || req.query.password; 16 var paramPassword = req.body.password || req.query.password;
15 //GET, POST 모두 고려해서 둘 다 검사 17 //GET, POST 모두 고려해서 둘 다 검사
16 18
17 - res.writeHead('200', { 'Content-Type': 'text/html;charset=utf8' }); 19 + // 데이터베이스 객체 참조
18 - res.write('<h1>Result form Express Server</h1>'); 20 + var database = req.app.get('database');
19 - res.write('<div><p>Param id : ' + paramId + '</p></div>'); 21 +
20 - res.write('<div><p>Param password : ' + paramPassword + '</p></div>'); 22 + // 데이터베이스 객체가 초기화된 경우, authUser 함수 호출하여 사용자 인증
21 - res.write("<br><br><a href ='/login.html'>로그인 페이지로 돌아가기</a>"); 23 + if (database.db) {
24 + authUser(database, paramId, paramPassword, function(err, docs) {
25 + // 에러 발생 시, 클라이언트로 에러 전송
26 + if (err) {
27 + console.error('사용자 로그인 중 에러 발생 : ' + err.stack);
28 +
29 + res.writeHead('200', {'Content-Type':'text/html;charset=utf8'});
30 + res.write('<h2>사용자 로그인 중 에러 발생</h2>');
31 + res.write('<p>' + err.stack + '</p>');
32 + res.end();
33 +
34 + return;
35 + }
36 +
37 + // 조회된 레코드가 있으면 성공 응답 전송
38 + if (docs) {
39 + console.dir(docs);
40 +
41 + // 조회 결과에서 사용자 이름 확인
42 + var username = docs[0].name;
43 +
44 + res.writeHead('200', {'Content-Type':'text/html;charset=utf8'});
45 + res.write('<h1>로그인 성공</h1>');
46 + res.write('<div><p>사용자 아이디 : ' + paramId + '</p></div>');
47 + res.write('<div><p>사용자 이름 : ' + username + '</p></div>');
48 + res.write("<br><br><a href='/login'>다시 로그인하기</a>");
49 + res.end();
50 +
51 + } else { // 조회된 레코드가 없는 경우 실패 응답 전송
52 + res.writeHead('200', {'Content-Type':'text/html;charset=utf8'});
53 + res.write('<h1>로그인 실패</h1>');
54 + res.write('<div><p>아이디와 패스워드를 다시 확인하십시오.</p></div>');
55 + res.write("<br><br><a href='/login'>다시 로그인하기</a>");
22 res.end(); 56 res.end();
57 + }
58 + });
59 + } else { // 데이터베이스 객체가 초기화되지 않은 경우 실패 응답 전송
60 + res.writeHead('200', {'Content-Type':'text/html;charset=utf8'});
61 + res.write('<h2>데이터베이스 연결 실패</h2>');
62 + res.write('<div><p>데이터베이스에 연결하지 못했습니다.</p></div>');
63 + res.end();
64 + }
65 +
23 }); 66 });
24 67
68 +//사용자를 인증하는 함수 : 아이디로 먼저 찾고 비밀번호를 그 다음에 비교하도록 함
69 +var authUser = function(database, id, password, callback) {
70 + console.log('authUser 호출됨.');
71 +
72 + // 1. 아이디를 이용해 검색
73 + database.UserModel.findById(id, function(err, results) {
74 + if (err) {
75 + callback(err, null);
76 + return;
77 + }
78 +
79 + console.log('아이디 [%s]로 사용자 검색결과', id);
80 + console.dir(results);
81 +
82 + if (results.length > 0) {
83 + console.log('아이디와 일치하는 사용자 찾음.');
84 +
85 + // 2. 패스워드 확인 : 모델 인스턴스를 객체를 만들고 authenticate() 메소드 호출
86 + var user = new database.UserModel({id:id});
87 + var authenticated = user.authenticate(password, results[0]._doc.salt, results[0]._doc.hashed_password);
88 + if (authenticated) {
89 + console.log('비밀번호 일치함');
90 + callback(null, results);
91 + } else {
92 + console.log('비밀번호 일치하지 않음');
93 + callback(null, null);
94 + }
95 +
96 + } else {
97 + console.log("아이디와 일치하는 사용자를 찾지 못함.");
98 + callback(null, null);
99 + }
100 +
101 + });
102 +
103 +}
104 +
25 module.exports = router 105 module.exports = router
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -53,9 +53,9 @@ ...@@ -53,9 +53,9 @@
53 <div class="row justify-content-center"> 53 <div class="row justify-content-center">
54 <div class="col-lg-8 col-xxl-6"> 54 <div class="col-lg-8 col-xxl-6">
55 <div class="text-center my-5"> 55 <div class="text-center my-5">
56 - <h1>로그인</h1> 56 + <h1>회원가입</h1>
57 <br> 57 <br>
58 - <form method="post" action="/login/process"> 58 + <form method="post" action="/signup/process">
59 <table> 59 <table>
60 <tr> 60 <tr>
61 <td><label>이름</label></td> 61 <td><label>이름</label></td>
......
1 -../ejs/bin/cli.js
...\ No newline at end of file ...\ No newline at end of file
1 +#!/bin/sh
2 +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3 +
4 +case `uname` in
5 + *CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
6 +esac
7 +
8 +if [ -x "$basedir/node" ]; then
9 + exec "$basedir/node" "$basedir/../ejs/bin/cli.js" "$@"
10 +else
11 + exec node "$basedir/../ejs/bin/cli.js" "$@"
12 +fi
......
1 -../jake/bin/cli.js
...\ No newline at end of file ...\ No newline at end of file
1 +#!/bin/sh
2 +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3 +
4 +case `uname` in
5 + *CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
6 +esac
7 +
8 +if [ -x "$basedir/node" ]; then
9 + exec "$basedir/node" "$basedir/../jake/bin/cli.js" "$@"
10 +else
11 + exec node "$basedir/../jake/bin/cli.js" "$@"
12 +fi
......
1 -../mime/cli.js
...\ No newline at end of file ...\ No newline at end of file
1 +#!/bin/sh
2 +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3 +
4 +case `uname` in
5 + *CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
6 +esac
7 +
8 +if [ -x "$basedir/node" ]; then
9 + exec "$basedir/node" "$basedir/../mime/cli.js" "$@"
10 +else
11 + exec node "$basedir/../mime/cli.js" "$@"
12 +fi
......
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
...@@ -11,10 +11,15 @@ ...@@ -11,10 +11,15 @@
11 "dependencies": { 11 "dependencies": {
12 "body-parser": "^1.20.0", 12 "body-parser": "^1.20.0",
13 "bootstrap": "^5.1.3", 13 "bootstrap": "^5.1.3",
14 + "cookie-parser": "^1.4.6",
15 + "crypto": "^1.0.1",
14 "ejs": "^3.1.7", 16 "ejs": "^3.1.7",
15 "express": "^4.18.1", 17 "express": "^4.18.1",
16 "express-error-handler": "^1.1.0", 18 "express-error-handler": "^1.1.0",
19 + "express-session": "^1.17.3",
17 "http": "^0.0.1-security", 20 "http": "^0.0.1-security",
21 + "mongoose": "^6.3.4",
22 + "mysql": "^2.18.1",
18 "path": "^0.12.7", 23 "path": "^0.12.7",
19 "serve-static": "^1.15.0" 24 "serve-static": "^1.15.0"
20 } 25 }
......