Mongoose를 사용할 경우 몇가지 유용한 API를 제공하고 있다. 이중 virtual, method, pre에 대한 사용법을 알아보자. 예제는 로그인시 패스워드를 암호화 하는 코드를 가지고 파악해 본다
1. Schemas
- http://mongoosejs.com/docs/guide.html 의 Schemas에 대한 정의와 플러그인 확장이 가능하다
- 스키마 인스턴스를 만들었다면 여기에 methods, statics, indexes, virtuals, options등을 설정할 수 있다
- 플로그인들은 http://plugins.mongoose.com에서 검색가능하다. 현재 나는 _id에 대한 auto increase 기능을 잘 쓰고 있다
// 1) 스키마 만들기 : 도큐먼트 구조의 정의
var ComponentSchema = new mongoose.Schema({
_id : { type: Number },
name : { type: String },
type : { type: String },
config : { type: String },
updated_on : { type: Date, default: Date.now }
});
// 2) 플러그인 확장 & methods, statics, indexes, virtuals, options등 설정
ComponentSchema.plugin(autoinc.plugin, {
model : 'sd_component',
field : '_id',
start : 200000,
step : 1
});
// 3) 모델은 스키마 정의에 대한 컴파일된 생성자이다. Model 인스턴스를 통해서 몽고디비로부터 데이터를 CRUD한다
var Component = mongoose.model('sd_component', ComponentSchema);
- 샘플로 UserSchema 생성하기
var UserSchema = new mongoose.Schema({
username : {type:String, required:true , unique:true},
hashed_password : {type:String, required:true},
salt : {type:String, required:true}
});
2. Instance Methods
- 스키마가 만들어지고 난후 기본적으로 설정된 메소드를 상속받아 사용한다 예) findById
- 사용자 커스텀 메소드를 정의할 수 있다. 처리 결과를 return 한다.
- statics는 callback을 파라미터로 넘기고, return이 없다. (참조)
// 메소드안에서 메소드 호출이 가능하다
UserSchema.method('authenticate', function(plainText) {
console.log('authenticate called:')
console.log('plain text = ' + plainText)
console.log('hashed = ' + this.encryptPassword(plainText))
console.log('db password= ' + this.hashed_password)
return this.encryptPassword(plainText) === this.hashed_password;
});
UserSchema.method('makeSalt', function() {
return Math.round((new Date().valueOf() * Math.random())) + '';
});
// crypto 모듈 사용하여 암호화
UserSchema.method('encryptPassword', function(password) {
return crypto.createHmac('sha1', this.salt).update(password).digest('hex');
});
UserSchema.method('generateToken', function() {
return crypto.createHash('md5').update(this.username + Date().toString()).digest("hex");
});
3. Virtual
- MongoDB에 저장되지 않는 편리한 Attribute이다 (참조)
- set/get 펑션을 정의한다
UserSchema.virtual('password')
.set(function(password) {
this._password = password;
this.salt = this.makeSalt(); // 사용자정의 메소드 호출
this.hashed_password = this.encryptPassword(password); // 사용자정의 메소드 호출
})
.get(function() { return this._password; });
// 모델 생성
var User = mongoose.model('User', UserSchema);
User.password = '1234'; // set
console.log(User.password); // get
4. Pre
- 몽구스의 middleware기능이다
- init, validate, save, remove 메소드 수행시 처리되는 미들웨어 펑션이다
- 복잡한 유효성검사, 트리거 이벤트 처리등. 예로 사용자를 삭제하면 사용자 관련 블로그포스트도 삭제하기같은 경우 사용
또는 에러 핸들링
UserSchema.pre('save', function(next) {
this.token = this.generateToken();
if (!validatePresenceOf(this.password || this.hashed_password)) {
next(new Error('Invalid password'));
} else {
next();
}
});
function validatePresenceOf(value) {
return value && value.length;
}
// ex)
User.save(function(err) { console.log(err.message); } );
- post : 사후처리
5. 전체 소스 코드
- User Model을 모듈로 만든다. User.js
- 애플리케이션에서는 User.js를 Model 인스턴스를 리턴받아서 사용한다
- Express의 Middleware에서 사용자 로그인시에 User.authenticate을 호출하여 패스워드를 암호화 한다
var mongoose = require('mongoose'),
crypto = require('crypto');
module.exports = function () {
var UserSchema = new mongoose.Schema({
username : {type:String, required:true , unique:true},
hashed_password : {type:String, required:true},
salt : {type:String, required:true}
});
UserSchema.virtual('password')
.set(function(password) {
this._password = password;
this.salt = this.makeSalt();
this.hashed_password = this.encryptPassword(password);
})
.get(function() { return this._password; });
UserSchema.method('authenticate', function(plainText) {
console.log('authenticate called:')
console.log('plain text = ' + plainText)
console.log('hashed = ' + this.encryptPassword(plainText))
console.log('db password= ' + this.hashed_password)
return this.encryptPassword(plainText) === this.hashed_password;
});
UserSchema.method('makeSalt', function() {
return Math.round((new Date().valueOf() * Math.random())) + '';
});
UserSchema.method('encryptPassword', function(password) {
return crypto.createHmac('sha1', this.salt).update(password).digest('hex');
});
UserSchema.method('generateToken', function() {
return crypto.createHash('md5').update(this.username + Date().toString()).digest("hex");
});
UserSchema.pre('save', function(next) {
this.token = this.generateToken();
if (!validatePresenceOf(this.password || this.hashed_password)) {
next(new Error('Invalid password'));
} else {
next();
}
});
return mongoose.model('User', UserSchema);
}
function validatePresenceOf(value) {
return value && value.length;
}
<참조>
'MongoDB > Prototyping' 카테고리의 다른 글
[MongoDB] Master/Slave 만들기 (0) | 2013.07.27 |
---|---|
[MongoDB] Index 생성/삭제하기 (0) | 2013.07.27 |
[Mongoose] Foreign Key 설정 및 Auto Increment Number 플러그인 (0) | 2013.05.28 |
[MongoDB] node.js에서 mongoose 외 기타 클라이언트모듈 통하여 연결하기 (0) | 2013.02.16 |
[MongoDB] mongos 통하여 Sharding 환경 구성하기 (1) (0) | 2013.01.05 |