1. DB 연결자, Router 연결자 - config.js
2. DB 관련
① Schema 정보 (스키마생성&스키마메소드추가) - user_schema.js
② database 객체에 DB정보, Schema정보, Schema Model 정보 추가 - database.js
(config.js, user_shema.js에 접근하여 모델객체 생성)
3. 라우팅 관련
ⓛ config.js 에 있는 Router 연결자 정보를 이용해 상황별 메소드에 접근 - router_loader.js
② UserModel 객체에 접근하여 결과 페이지 view단을 만듬 - user.js
4. 메인 파일 - app2.js
개발환경 - os: Window8.1 64x / 프로세서: Intel(R) Core(TM) i3-4020Y CPU @ 1.50GHz / RAM: 8.0GB
개발도구 - IDE: eclipse 4.4.2 (32bit) / DBMS: Oracle11g / 컴파일러: jdk 1.8.0 (java version)
개발언어 - Java, HTML5, CSS3, JavaScript(Node.js), SQL, jQuery
<전체 경로>
1. DB 연결자, Router 연결자 - config.js
module.exports = {
server_port:3000,
db_url:"mongodb://localhost:27017/shopping",
// 스키마 위치지정, db:user3, 스키마이름, 모델이름
db_schemas:[
{file:"./user_schema",collection:"users3",
schemaName:"UserSchema",modelName:"UserModel"}
],
//라우터 정보
route_info:[
{file:"./user", path:"/process/login",
method:"login", type:"post"},
{file:"./user", path:"/process/addUser",
method:"addUser", type:"post"},
{file:"./user", path:"/process/listUser",
method:"listUser", type:"post"}
]
}
2. DB 관련
① Schema 정보 (스키마생성&스키마메소드추가) - user_schema.js
<내가 정의한 스키마 객체에 메소드를 추가하는 방법>
방법1. static 이용
방법2. 메소드 추가
<로그인 인증 메소드 원리>
//인증메소드 (입력된 비밀번호와 비교: true/false)
UserSchema.method("authenticate",
function(inputPwd,inSalt,hashed_pwd){ // hashed_pwd: 이미 저장된 pwd
if(inSalt) { // 넘어온 key값이 있다면
return this.encryptPwd(inputPwd,inSalt)
=== hashed_pwd;
} else { // 없어도
return this.encryptPwd(inputPwd)
=== this.hashed_pwd;
}
DB에 저장된 Key값과 사용자가 입력한 패스워드를 다시 암호화 - encryptPwd() 하여
DB에 저장된 hashed_pwd와 비교한다 (DB에는 123이란 패스워드 데이터가 없고 암호화된 데이터만 저장돼있기 때문)
salt = key 값 != hashed_pwd
//Schema 정보
var crypto = require("crypto");
var Schema = {};
Schema.createSchema = function(mongoose) {
UserSchema = mongoose.Schema({
id: {type:String, required:true, unique:true, "default":""}, // default, 없으면 null
hashed_pwd: {type:String, required:true, unique:true, "default":""}, // 암호화된 패스워드 저장하는 공간, 단순히 123이 저장되는게 아님
salt: {type:String, required:true}, // 암호화를 할 때 만들어지는 일종의 값
// 왜 String인가? crypt : 랜덤 값(key) + 사용자가 입력한 패스워드(ex. 123) 합쳐서 암호화를 시킴
// 123만 암호화 안되고 반드시 key를 줘야함
// (salt는 그냥 고정 키값을 줘도 됨. 임의의값 아무거나 있으면 되는것 )
name: {type:String, index:"hashed","default":""}, // name에 index 추가
age : {type:Number,"default":20},
created_at: {type:Date, index:{unique:false},"default":Date.now}, // 날짜는 중복값이 들어가도 상관 없으니깐
updated_at: {type:Date, index:{unique:false},"default":Date.now} // 수정 날짜
});
/*
* 가상스키마영역, 실제존재하는속성이 아님
*/
UserSchema
.virtual("pwd") //pwd: 사용자가 넘겨주는 실제 패스워드
.set(function(pwd) {
this._pwd = pwd;
this.salt = this.makeSalt();// 암호화를 하기 위해 key 하나가 만들어짐 (내가 만드는게 아님) => key값 생성
//salt라는 속성이 만들어지면서 makeSalt() 메소드를 호출
// 결과값으로 복잡한 숫자를 돌려받음
this.hashed_pwd =
this.encryptPwd(pwd); // 위의 salt 키값을 가지고 내가 입력한 pwd를 암호화시켜서 hashed_pwd에 넣는다
})
.get(function(){
return this._pwd;
});
// <Schema> 객체에 메소드를 추가 (방법1. static, 방법2. method)
// 스키마 객체의 모델 인스턴스 객체에 메소드 추가 - 방법2 이용
// 총 method 3개 만듬 - encryptPwd, makeSalt, authenticate
//입력된 패스워드와 키를 합쳐서 암호화시키는 작업을 하는 메소드
UserSchema.method("encryptPwd",function(inputPwd,inSalt){
// plain = text(일반문자)
if(inSalt) { // inSalt가 있으면, 합쳐서 암호화시켜라
return crypto.createHmac("sha1",inSalt) // insalt와 inputpwd를 합쳐서 암호화
.update(inputPwd).digest("hex");
// sha(쉬바) - 암호화하는방법, hex(헥사)
} else {
return crypto.createHmac("sha1",this.salt) // inSalt가 없어도, 합쳐서 암호화
.update(inputPwd).digest("hex");
}
});
//salt값 만드는 메소드
UserSchema.method("makeSalt",function(){
console.log("VOF- "+new Date().valueOf());
console.log("MATH- " + Math.random());
return Math.round((new Date().valueOf() * Math.random())) + "";
});
//인증메소드 (입력된 비밀번호와 비교: true/false)
UserSchema.method("authenticate",
function(inputPwd,inSalt,hashed_pwd){ // hashed_pwd: 이미 저장된 pwd
if(inSalt) { // 넘어온 key값이 있다면
return this.encryptPwd(inputPwd,inSalt)
=== hashed_pwd;
} else {
return this.encryptPwd(inputPwd)
=== this.hashed_pwd;
}
});
//<Schema> 객체에 메소드를 추가 (방법1. 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 = Schema;
// 위의 코드를 외부에서 사용할 수 있게끔 해주는것임
// 반드시 있어야함
② database 객체에 DB정보, Schema정보, Schema Model 정보 추가 - database.js
/**
* http://usejsdoc.org/
*/
var mongoose = require("mongoose");
// database 객체에 db, schema, model 정보 추가
var database = {};
// 이전 예제에서 만든 init안쓰고, 여기서 새로 생성
// 초기화를 위해 호출하는 함수 (app:express 서버객체)
database.init = function(app,config) {
connect(app,config);
};
// 데이터베이스에 연결하고 응답 객체의 속성으로 db객체 추가
function connect(app,config) {
// 몽구스로 데이터베이스 연결
mongoose.connect(config.db_url);
database = mongoose.connection;
database.on("error",
console.error.bind(console,"몽구스 연결 에러.."));
database.on("open",function(){
console.log("데이터 베이스에 연결됨 " + config.db_url);
//user 스키마 및 모델 객체 생성
createUserSchema(app,config);
});
database.on("disconnected",function(){
console.log("연결이 끊어졌습니다, 5초후 재연결 합니다");
setInterval(connectDB,5000); // 5초 후 다시 연결
});
}
function createUserSchema(app,config) {
var schemaLen = config.db_schemas.length; //4개
for(var i=0; i<schemaLen; i++) {
var curItem = config.db_schemas[i];
// 모듈(config.js)에서 모듈(user_schema.js)을 불러온 후
// createSchema()함수 호출
var curSchema =
require(curItem.file).createSchema(mongoose);
// =>결과적으로 user_schema.js의 createSchema를 불러온 것
// 그렇게 만든 스키마를 Model에 적용
var curModel =
mongoose.model(curItem.collection,curSchema);
//collection = 즉 user3 테이블을 가져와서 모델 생성
// database 객체에 속성으로 스키마, 모델 추가
database[curItem.schemaName] = curSchema;
database[curItem.modelName] = curModel;
}
app.set("database",database); // db 정보 + 스키마정보 + 모델정보
}
module.exports = database;
3. 라우팅 관련
ⓛ config.js 에 있는 Router 연결자 정보를 이용해 상황별 메소드에 접근 - router_loader.js
var routerLoader ={};
var config = require("../config");
routerLoader.init = function(app,router) {
console.log("routerLoader.init 호출됨");
return initRouter(app,router);
};
function initRouter(app,router) {
var infoLen = config.route_info.length;
for(var i=0; i<infoLen; i++) {
var curItem = config.route_info[i];
var curModule = require(curItem.file); // user.js 를 받아옴
// 라우팅 처리
if(curItem.type=="get") {
//router.route("/process/login").get(login); 원래 이걸 읽는건데 이걸 변수로 변환하면
router.route(curItem.path).get(curModule[curItem.method]);
// curItem.method는 login을 뜻하니깐
} else if(curItem.type=="post") {
router.route(curItem.path).post(curModule[curItem.method]);
}
}
//미들웨어등록
app.use("/",router);
}
// 이렇게 변수화 처리함으로써
// router.route("/process/login").post(user.login);
// 이렇게 여러개 일일이 쓰던걸 간편하게 모듈화 시킨것임
module.exports = routerLoader;
② UserModel 객체에 접근하여 결과 페이지 view단을 만듬 - user.js
addUser, authUser - 이 파일에서 내부적으로 사용하는 함수 - 외부에서 사용하는게 아니므로 빼낼 필요가 없다
login, addUsers, listUser - 이 3개 메소드만 다른 파일에서 접근할 수 있게 module.exports 시켜주면 된다
//데이터베이스 객체, 스키마 객체, 모델 객체를 user모듈에서 사용할 수 있도록 전달
var database;
var UserSchema;
var UserModel;
var login = function(req,res) {
console.log("user.js의 login 호출됨...");
var paramId = req.body.id || req.query.id;
var paramPwd = req.body.pwd || req.query.pwd;
var database = req.app.get("database");
if(database){
authUser(database, paramId, paramPwd,
function(err,result){
if(err) {
res.writeHead("200",
{"Content-Type":"text/html;charset=utf-8"});
res.write("<meta name='viewport' content='width=device-width, height=device-height, initial-scale=1'/>");
res.write("<h1>로그인 에러!</h1>");
res.end();
return;
}
// 조회가 제대로 된 경우
if(result){
var userName = result[0].name;
console.log ("조회됐습니다");
res.writeHead("200",
{"Content-Type":"text/html;charset=utf-8"});
res.write("<meta name='viewport' content='width=device-width, height=device-height, initial-scale=1'/>");
res.write("<h1>로그인성공!</h1>");
res.write("<div>아이디: " + paramId + "</div>");
res.write("<div>이름: " + userName + "</div>");
res.write("<br/><br/><a href='/public1/login.html'>" + "다시입력</a>");
res.end();
} else { // 조회된 데이터가 없는경우
console.log ("조회안됐습니다");
res.writeHead("200",
{"Content-Type":"text/html;charset=utf-8"});
res.write("<meta name='viewport' content='width=device-width, height=device-height, initial-scale=1'/>");
res.write("<meta name='viewport' content='width=device-width, height=device-height, initial-scale=1'/>");
res.write("<h1>로그인실패!</h1>");
res.write("<div>아이디와 비밀번호를 다시 확인하세요</div>"); // 문자 div없이 그냥쓰면 텍스트처리되어버림
res.write("<br/><br/><a href='/public1/login.html'>" + "다시입력</a>");
res.end();
}
});
}
else { // db연결 실패 시
res.writeHead("200",
{"Content-Type":"text/html;charset=utf-8"});
res.write("<meta name='viewport' content='width=device-width, height=device-height, initial-scale=1'/>");
res.write("<div>database연결하지못했습니다</div>")
res.write("<h1>db연결 실패!</h1>");
res.write("<br/><br/><a href='/public1/login.html'>" + "다시입력</a>");
res.end();
}
};
var addUsers = function(req,res) {
var paramId = req.body.id || req.query.id;
var paramPwd = req.body.pwd || req.query.pwd;
var paramName = req.body.name || req.query.name;
var database = req.app.get("database");
// database가 연결 되었으면,
if(database){
console.log("db연결성공!");
addUser(database,paramId,paramPwd,paramName,
function(err,result){
if(err) {
res.writeHead("200",
{"Content-Type":"text/html;charset=utf-8"});
res.write("<meta name='viewport' content='width=device-width, height=device-height, initial-scale=1'/>");
res.write("<h1>사용자 추가 에러!</h1>");
res.end();
return;
}
// 여기서 확실히 입력되었는지 다시 한번 검사
if(result){
console.log("사용자 추가 성공!")
res.writeHead("200",
{"Content-Type":"text/html;charset=utf-8"});
res.write("<meta name='viewport' content='width=device-width, height=device-height, initial-scale=1'/>");
res.write("<h1>사용자 추가 성공</h1>");
res.write("<br/><br/><a href='/public1/login.html'>" + "로그인</a>");
res.end();
} else {
res.writeHead("200",
{"Content-Type":"text/html;charset=utf-8"});
res.write("<meta name='viewport' content='width=device-width, height=device-height, initial-scale=1'/>");
res.write("<h1>사용자 추가 실패</h1>");
res.end();
}
});
} else { // db연결 안됨
res.writeHead("200",
{"Content-Type":"text/html;charset=utf-8"});
res.write("<meta name='viewport' content='width=device-width, height=device-height, initial-scale=1'/>");
res.write("<h1>db연결 실패!</h1>");
res.write("<br/><br/><a href='/public1/addUser.html'>" + "다시입력</a>");
res.end();
}
};
var listUser = function(req,res) {
console.log("/process/listUser 호출됨...");
var database = req.app.get("database");
if(database){
//1. 모든 사용자 검색
// Model 객체 생성
database.UserModel.findAll(function(err,result){
// 조회 실패
if(err) {
res.writeHead("200",
{"Content-Type":"text/html;charset=utf-8"});
res.write("<meta name='viewport' content='width=device-width, height=device-height, initial-scale=1'/>");
res.write("<h1>사용자 리스트 조회 실패</h1>");
res.end();
return; // 더이상 실행하면 안되니깐 return
}
// 조회 성공
if(result){
res.writeHead("200",
{"Content-Type":"text/html;charset=utf-8"});
res.write("<meta name='viewport' content='width=device-width, height=device-height, initial-scale=1'/>");
res.write("<h1>사용자 리스트</h1>");
res.write("<div><ul>");
for(var i=0; i<result.length; i++) {
var curId = result[i]._doc.id;
var curName = result[i]._doc.name;
var curAge = result[i]._doc.age;
res.write("<li>#" + (i+1) + ":"
+ curId + ", "
+ curName + ", "
+ curAge + "</li>");
}
res.write("</ul></div>");
res.end();
} else {
res.writeHead("200",
{"Content-Type":"text/html;charset=utf-8"});
res.write("<meta name='viewport' content='width=device-width, height=device-height, initial-scale=1'/>");
res.write("<h1>사용자 리스트 조회 실패2</h1>");
res.end();
}
});
} else {
res.writeHead("200",
{"Content-Type":"text/html;charset=utf-8"});
res.write("<meta name='viewport' content='width=device-width, height=device-height, initial-scale=1'/>");
res.write("<h1>db연결 실패!</h1>");
res.end();
}
};
//사용자를 인증하는 함수
var authUser = function(database,id,pwd,callback) {
//id,pw 검색해오기
database.UserModel.findById(id,function(err,result){
if(err){
callback(err,null); // 데이터 null
console.log("찾는 id가 없습니다");
return;
}
// 조회한 데이터가 있는 경우 콜백함수를 호출하면서 결과를 전달한다
if(result.length>0){ // 아이디가 일치하면
console.log("id 일치함");
// 모델 인스턴스 객체 생성 후 로그인 인증 메소드를 호출
var user = new database.UserModel({id:id});
var authenticate =
user.authenticate(pwd,
result[0]._doc.salt,
result[0]._doc.hashed_pwd); // 이 3개를 호출함
if(authenticate) {
console.log("비밀번호가 일치합니다");
callback(null,result);
} else {
//비밀번호 일치 안하는 경우
console.log("비밀번호가 일치X");
callback(null,null);
}
} else {
// 아이디가 틀렸을 때
console.log("일치하는 사용자를 찾지 못함");
callback(null,null); // 에러도 안나고 데이터도 없으니깐 null로 처리
}
});
}
//사용자 추가 함수
var addUser = function(database,id,pwd,name,callback){
// UserModel 인스턴스 생성 (3개의 값을 가지고)
var user = new database.UserModel({"id":id,"pwd":pwd,"name":name});
// 입력 - 들어가는 데이터는 json형태니깐 [{}]
user.save(function(err,result){
//이 save시킬 때, 가상 스키마 영역으로 가서 암호화 작업이 이뤄지며 저장됨
if(err){
throw err;
}
console.log("사용자 추가됨");
callback(null,result);
//callback(에러x, result값반환);
});
}
module.exports.login = login;
module.exports.addUser= addUsers;
module.exports.listUser = listUser;
4. 메인 파일 - app2.js
var express = require("express");
var http = require("http");
var path = require("path");
var bodyParser = require("body-parser");
var serveStatic = require("serve-static");
var expressErrorHandler = require("express-error-handler");
var errorHandler = require("errorhandler");
var expressSession = require("express-session");
//var mongoose = require("mongoose"); 필요X - database.js에있음
//user.js 모듈 추가
var user = require("./router/user");
//config.js 모듈 추가
var config = require("./config");
//config.js를 config란 새폴더 생성해서 안으로 넣어놔도됨 ../ 보여주려고 따로 빼놓은것
//database.js 모듈 추가
var database = require("./database/database");
//router_loader.js 모듈 추가
var routerLoader = require("./router/router_loader");
var app = express();
app.set("port",process.env.PORT || config.server_port); // 3000
app.use(bodyParser.urlencoded({extended:false}));
app.use(bodyParser.json());
app.use("/public1",serveStatic(path.join(__dirname,"public1")));
app.use(expressSession({
secret:"myKey", // 사용자 정의 세션 이름
resave:true,
saveUninitialized:true
}));
//라우팅 함수 등록 : var router = express.Router(); 이렇게 하던거를 아래와 같이
// express.Router() : 라우터객체 바로 넘김
routerLoader.init(app,express.Router());
//404 에러 처리
var errorHandler = expressErrorHandler({
static:{
"404":"./public/404.html"
}
});
//미들웨어 등록
app.use(expressErrorHandler.httpError(404)); //404에러가 났을 때 실행해라
app.use(errorHandler);
// host번호 부여
var host = "192.168.16.14";
//Express 서버 시작
http.createServer(app).listen(app.get("port"),host,function(){
console.log("서버를 시작했습니다");
database.init(app,config);
});
이제 localhost로 접속안하고 host번호를 부여한다.
db_url : "mongodb://localhost:27017/shopping" - DB는 내꺼니까 localhost 안 바꿔도 된다
'Node' 카테고리의 다른 글
Passport 모듈로 회원가입 및 로그인 하기 (모듈화 적용 X) (1) | 2019.11.11 |
---|---|
Node.js 에 View Template 적용하기 (1) - Semantic UI (미완) (0) | 2019.11.08 |
Node.js + Oracle (0) | 2019.11.06 |
Node.js + MongoDB (0) | 2019.11.04 |
Node.js - 웹 서버 구축 (Express 미들웨어) (0) | 2019.11.04 |