Server_Side
userModel
UserModel은 Schema를 감싸 주는 역할을 한다
Schema란 무엇인가?
Schema는 데이터베이스를 구성하는 데이터 개체, 속성, 관계 및 데이터조작 시 데이터 값들이 갖는 제약 조건 등에 대해 전반적으로 정의한다.
const userSchema = mongoose.Schema({
name: {
type: String,
maxlength: 50
},
email: {
type: String,
trim: true,
unique: 1
},
password: {
type: String,
minglength: 5
},
lastname: {
type: String,
maxlength: 50
},
role: {
type: Number,
default: 0
},
image: String,
token: {
type: String,
},
tokenExp: {
type: Number
}
})
Schema의 특징
- Schema는 Data Dictionary에 저장된다
- Data Dictionary : 시스템 전체에서 나타나는 데이터 항목들에 대한 정보를 지정한 중앙 저장소로, 이 정보에는 항목을 참조하는데 사용되는 식별자, 엔티티의 구성요소, 항목을 참조하는 곳 등이 포함
- 특정 데이터 모델을 이용해서 만들어진다.
- 시간에 따라 불변이다.
- 데이터의 구조적 특성을 의미한다.
- 인스턴스에 의해 규정된다.
Git이란?
git은 형상 관리 도구중 하나이다.
- 형상 관리 도구 즉, 버전 관리 시스템 중의 하나로 기업의 소스코드를 효과적으로 관리할수 있게 해주는 무료, 공개 소프트웨어이다.
git은 분산형 관리 시스템이다.
- 소스코드를 여러 개발PC와 저장소에 분산해서 저장하기 때문에 중앙서버에 장애가 발생해도 로컬저장소에 커밋할수 있으며, 복원도 가능하다.
여러명이 동시 작업이 가능하다.
- 브랜치를 통해 개발한뒤에 합치는 방식으로 개발을 진행한다.
- 팀이아닌 개인 프로젝트라도 Git을 통해 버전 관리를 하기 수월하다.(pull을 통해 업데이트, patch를 통해 파일 배포)
(사진 출처: http://pismute.github.io/whygitisbetter/images/local-remote.png)
-
Repository : 저장소를 의미하며, 저장소는 히스토리, 태그, 소스의 가지치기 혹은 branch에 따라 버전을 저장한다. 저장소를 통해 작업자가 변경한 모든 히스토리를 확인 할 수 있다.
-
Working Tree : 작업자의 현재 시점.
-
Staging Area : 저장소에 커밋하기 전에 커밋을 준비하는 위치.
-
Commit : 현재 변경된 작업 상태를 점검을 마치면 확정하고 저장소에 저장하는 작업.
-
Head : 현재 작업중인 Branch
-
Branch : 가지 또는 분기점을 의미하며, 작업을 할때에 현재 상태를 복사하여 Branch에서 작업을 한 후에 완전하다 싶을때 Merge를 하여 작업을 한다.
-
Merge : 다른 Branch의 내용을 현재 Branch로 가져와 합치는 작업을 의미한다.
Bcrypt
단방향 암호화를 위해 만들어진 Hash 함수
기존 해쉬 함수들은 rainbow table attack(미리 Hash값들으 계산해놓은 테이블로 원래 정보를 찾아내는 해킹방법)에 취약함
Salting과 키 스트레칭
Salting
- 실제 정보 이외에 추가적으로 무작위 데이터를 더해서 Hash값을 계산하는 방법.
- salt로 인해 Hash값이 달라지기 때문에 rainbow attack 같이 미리 Hash값을 계산하는 공격을 무효화 시킨다.
- salt 자체는 비밀이 아니고 Hash값을 바꾸는데 목적이 있다. 따라서 같은 비밀번호라도 Hash값이 달라지게 된다.
키 스트레칭
- 단방향 Hash값을 계산한후 그 Hash값을 다시 Hash하고, 이를 반복한다. Hash의 반복횟수를 추가하여 계쏙 보완할 수 있다.
Bcrypt는 이러한 Salting과 키 스트레칭을 구현한 대표적인 함수다.
- Alg : Algorithm 알고리즘 식별자 는 bcrypt를 뜻한다.
- Cost : Cost factor 키 스트레칭 한 횟수. 2^n으로 은 2^10 즉 1024 이다.
- Salt : 128비트 Salt, 22자 base 64로 인코딩
- Hash : Salting과 키 스트레칭 후 Hash 값
How to use Bcrypt?
https://www.npmjs.com/package/bcrypt
NPM 공식 사이트에서 Install 및 usage 방법을 숙지, 프로젝트에 적용
userSchema.pre('save', function (next) {
var user = this;
if (user.isModified('password')) {
bcrypt.genSalt(saltRounds, function (err, salt) {
if (err) return next(err);
bcrypt.hash(user.password, salt, function (err, hash) {
if (err) return next(err);
user.password = hash
next()
})
})
} else {
next()
}
});
user모델에서 user정보를 받아온뒤 password를 hash함수로 암호화
userSchema.methods.comparePassword = function (plainPassword, cb) {
bcrypt.compare(plainPassword, this.password, function (err, isMatch) {
if (err) return cb(err);
cb(null, isMatch)
})
}
로그인 시 비밀번호를 check한뒤 일치하면 null값을 리턴하도록 callback함수로 지정한다
JsonWebToken
전자 서명 된 URL-safe (URL로 이용할 수있는 문자 만 구성된)의 JSON으로
전자 서명은 JSON 의 변조를 체크 할 수 있게되어 있다
JWT는 서버와 클라이언트 간 정보를 주고 받을 때 Http 리퀘스트 헤더에 JSON 토큰을 넣은 후 서버는 별도의 인증 과정없이 헤더에 포함되어 있는 JWT 정보를 통해 인증
JWT장점
- 인증에 필요한 모든 정보를 토큰이 포함하고 있기 때문에 별다른 인증 저장소가 필요없다.
- 디버깅 및 관리가 용이하다
- 트레픽에 대한 부담이 적다
How To Use JWT?
https://www.npmjs.com/package/jsonwebtoken
npm 공식 페이지에서 나온대로 사용한다. 본 프로젝트에서는
userSchema.methods.generateToken = function (cb) {
var user = this;
console.log('user', user)
console.log('userSchema', userSchema)
var token = jwt.sign(user._id.toHexString(), 'secret')
var oneHour = moment().add(1, 'hour').valueOf();
user.tokenExp = oneHour;
user.token = token;
user.save(function (err, user) {
if (err) return cb(err)
cb(null, user);
})
}
로 토큰을 만든뒤에 user Schema에서 토큰 필드에 저장을 한다.
const userSchema = mongoose.Schema({
name: {
type: String,
maxlength: 50
},
email: {
type: String,
trim: true,
unique: 1
},
password: {
type: String,
minglength: 5
},
lastname: {
type: String,
maxlength: 50
},
role: {
type: Number,
default: 0
},
image: String,
token: {
type: String,
},
tokenExp: {
type: Number
}
})
저장된 토큰필드에서 토큰을 비교하여 쿠키에 저장된 토큰과 동일하면 loginSuccess:True를 반환
router.post("/login", (req, res) => {
User.findOne({ email: req.body.email }, (err, user) => {
if (!user)
return res.json({
loginSuccess: false,
message: "Auth failed, email not found"
});
user.comparePassword(req.body.password, (err, isMatch) => {
if (!isMatch)
return res.json({ loginSuccess: false, message: "Wrong password" });
user.generateToken((err, user) => {
if (err) return res.status(400).send(err);
res.cookie("w_authExp", user.tokenExp);
res
.cookie("w_auth", user.token)
.status(200)
.json({
loginSuccess: true, userId: user._id
});
});
});
});
});
Author And Source
이 문제에 관하여(Server_Side), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@dongmen5149/ServerSide저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)