oris9
자바스크립트 인증에 대해서 본문
인증
누군가의 신원을 확인
권한
특정 사용자가 가능한 행동을 확인하는 것. 보통 권한 부여는 사용자가 인증된 후 일어남
암호를 그대로 저장하면 안됨
해시함수로 암호를 처리해서 데이터베이스에 저장함 (해독불가능한 결과물)
해시함수(임의크기 데이터를 입력하면 고정된 크기의 데이터를 출력해줌)
암호화 해시함수, 암호화안전해시함수는 단방향 함수임. 역추적이 불가능함.
입력값에 작은변화가 있을 때 출력값에 큰 변화가 생김.
항상 동일한 값이 출력됨
정확히 똑같은 값이 출력될 확률이 매우 낮아야함
느려야함. 그래야 안전
솔트
추가 안전장치
다양한 사이트에서 같은 암호를 쓰는 사람이 많이 때문에 ..
역방향조회테이블을 만들지못하게하는방법임
시작이나 끝에 솔트를 추가해서..
솔트는 따로 기록해둬야함. 솔트는 무작위성 부여가 목적이라 숨길필요는 없음
BCRYPT
대표적인 해시 함수.
두가지 패키지가 있음
bcrypt.js -자바스크립트로만쓰여짐. 클라이언트에서도 실행될 수 있음 (axios가 브라우저에서 실행되는 것과 같이)
bcrypt(브라우저에서 실행되지않음. Node대상으로 작성됨. 서버가 대상임. C++로 구현됨. 조금더빠름.
'$ npm i bcrypt'
const bcrpyt = require("bcrypt")
// 암호 생성
const hashPassword = async (pw) => {
const salt = await bcrypt.genSalt(10);
// saltRound : 해시의 난이도. 해시난이도를 올리면 해시 계산 시간이 증가해 계산 속도를 늦출수있음(이상적인속도..250ms) - 요즘은 12정도가 추천됨
const hash = await bcrypt.hash(pw, salt);
console.log(salt);
console.log(hash);
}
hashPassword("monkey")
// 암호 생성 (간단 버전)
const hashPassword = async (pw) => {
const hash = await bcrypt.hash(pw, 10);
console.log(hash);
}
hashPassword("monkey")
// 암호 확인
const login = async (pw,hashedPw) => {
const result = await bcrypt.compare(pw, hashedPw);
if (result) {
console.log("로그인에 성공하였습니다")
} else {
console.log("비밀번호가 일치하지 않습니다")
}
}
login("monkey","아까 콘솔에 출력된 해시암호") // "로그인에 성공하였습니다"
login("mmmmmmmonkey","아까 콘솔에 출력된 해시암호") // "비밀번호가 일치하지 않습니다"
Express에서 적용하기
- 가입 구현 (아이디, 패스워드 등록)
app.post("/register", async(req, res) => {
const { password, username } = req.body;
const hash = await bcrypt.hash(password, 12);
const user = new User({
username,
password: hash
})
await user.save()
res.redirect("/")
})
2.로그인 구현
app.get("/login", async (req, res) => {
res.render("login")
}
app.post("/login", (req, res) => {
const { username , password } = req.body
const user = await User.findOne({ username }) // 우선 이 사용자이름을 가진 사용자를 찾음 ( -> 따라서 사용자이름은 중복x )
const validPassword = await bcrypt.compare(password, user.password)
if (vaildPassword) {
req.session.user_id = user._id; // 로그인에 성공하면 세션에 사용자ID를 저장하므로써 나중에 로그인 여부를 확인가능
// (express-session이용)
res.send("환영합니다")
} else {
res.send ("사용자 또는 비밀번호가 틀렸습니다") // 이때 특정 어떤 것이 틀렸다고 정보를 주면 안됨
)
})
로그인 여부 기억 (쿠기와 세션은 HTTP에 상태성을 부여하는 방법을 제공합니다) ---todo 링크로만들기
로그인이 되면 세션이 만료될때까지 로그인 상태가 유지됨
사용자가 로그인 되었는지 여부를 확인하고 ( 다양한 방법이 존재 - 예, 세션에 로그인한 사용자의 ID를 저장 )
- 로그아웃
app.post("/logout", (req, res) => {
req.session.user_id = null;
res.redirect("/login")
}
또는
app.post("/logout", (req, res) => {
req.session.destroy(); // 한 특성만 null로 설정하는게 아니라 세션 전체를 파기
// 특정 사용자에 대한 정보를 많이 저장해서 사용했을 때 사용한다
res.redirect("/login")
}
express router를 사용한다면 /admin이나 /commen처럼 /로 시작하는 라우터들이 있을텐데, 이 중 특정 라우터들은 로그인하지 않으면 접근하지 못하도록 만들 수 있다
(만약 보호할 라우터가 여러 개라면 express router를 별도의 파일로 분리하고 router 내 모든 라우트에 requireLogin 미들웨어를 적용하면 됨)
: 사용자 ID가 세션에 있는지 확인하는 미들웨어 만들기
const requireLogin = (req, res, next) => {
if (!req.session.user_id) {
return res.redirect("/login")
}
next();
}
리팩토링 :: 라우트 규모 축소하기
const mongoose = require("mongoose");
const bcrypt = require("bcrypt");
const userSchema = new mongoose.Schema(
... // User 구현
)
// statics 속성을 통해 모델에 추가할 수 있는 여러 메서드를 정의할 수 있음
userSchema.statics.findByUsernameAndValidate = async function(username, password) {
const foundUser = await this.findOne({ username })
const isValid = await bcrypt.compare(password, foundUser.password)
return isValid ? foundUser : false;
}
// 가입시에 해시된 암호를 User모델에 전달하는게 아니라, 저장될때 몽구스에서 자동으로 해시되어서 저장되도록
userSchema.pre("save", async function(next) {
if(!this.isModified("password")) return next() // password가 변경되었는지 참, 거짓으로 나타냄
this.password = await bcrypt.hash(this.password, 12)
next() // 이 경우에는 save를 호출함
})
module.exports = mongoose.model("User",userSchema)
app.post("/login", (req, res) => {
const { username , password } = req.body
const foundUser = await User.findByUsernameAndValidate(username, password)
if (foundUser) {
req.session.user_id = foundUser._id; /
res.send("환영합니다")
} else {
res.send ("사용자 또는 비밀번호가 틀렸습니다")
)
})
# Passport
Node에 인증을 추가해주는 라이브러리
'JavaScript' 카테고리의 다른 글
[Javascript] 파라미터? 인자? 헷갈리는 용어 정리와 argument 객체, 나머지 매개변수에 대해 알아보기 (0) | 2024.03.09 |
---|---|
웹브라우저에서의 저장소에 대해 알아보기 (로컬스토리지, 세션 저장소, IndexedDB) (0) | 2024.03.08 |
[javascript] 리터럴과 타입에 대해 정리하기 (0) | 2024.03.07 |
[Javascript] 클래스를 이해하고 모듈화 해보기 (0) | 2024.03.04 |
JavaScript의 동작원리에 대해 (0) | 2024.01.12 |