2022. 1. 5. 14:59ㆍ프로그래밍/개인프로젝트
POMOTODO를 만들면서 작성한 코드를 복습하기 위해 작성하는 글입니다.
Node.js의 라이브러리인 Express에서 Session을 이용해 인증을 구현하도록 한다
쿠키의 등장으로 이전에 통신했던 내역을 기억할 수 있게 되었다
하지만 쿠키가 유출될 수 있고 조작될 수 있기때문에 인증을 구현하는것은 매우 위험하다
세션을 적용해서 인증하도록 해서 쿠키를 암호화 할 수 있다.
세션은 각각의 사용자를 식별하기 위한 식별자로서만 기능하는것이고
이것에 대한 실제 데이터는 서버에 저장해서 안전하게, 훨씬 더 많은 정보를 저장할 수 있다
직접 구현하는것이 가능하지만 복잡하고 어렵기 때문에 Express의 도움을 받아서 쉽게 구현한다.
1. 터미널을 켜고 라이브러리를 설치한다
npm install passport passport-local express-session
2. server.js 상단에 설치한 라이브러리를 첨부해준다
//server.js
const express = require('express');
const app = express();
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const session = require('express-session');
// app.use()는 미들웨어를 쓰겠다는 말임
// 미들웨어 : app.use = request - response 중간에 실행되는 코드
app.use(session({
secret : 'secret code',
resave : true,
saveUninitialized: false,
cookie: {
httpOnly: true,
secure: false
}
}));
app.use(passport.initialize());
app.use(passport.session());
3. login.ejs를 작성한다
input태그의 name을 사용할 것이므로 기억해둔다 (loginId, loginPassword)
login.ejs
<!--login.ejs-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="apple-touch-icon" sizes="180x180" href="favicon/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="favicon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="favicon/favicon-16x16.png">
<link rel="manifest" href="favicon/site.webmanifest">
<link rel="mask-icon" href="favicon/safari-pinned-tab.svg" color="#5bbad5">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="theme-color" content="#ffffff">
<title>POMOTODO</title>
<link rel="stylesheet" href="login-signup.css" />
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script defer src="login.js"></script>
</head>
<body>
<div class="container">
<h1>log in</h1>
<div class="login-title-underline"></div>
<form method="post" name="loginForm" id="authForm" action="/loginPost">
<div class="form-list">
<input type="text" class="form-list" id="loginId" name="loginId" placeholder="username" minlength="5" maxlength="10" autocomplete='off' autofocus>
</div>
<div class="form-list">
<input type="password" class="form-list" id="loginPw" name="loginPassword" placeholder="password" minlength="5" maxlength="20" autocomplete='off'onkeydown="if(window.event.keyCode==13){printName()}">
</div>
<div class="id-check"><%= loginFeedback %></div>
<button type="button" class="form-list" id="form-login" onclick='printName()' >login</button>
<button type="button" class="form-list" id="login-toHome" onclick="location.href='/'">home</button>
<button type="button" class="form-list" id="login-toSignup" onclick="location.href='/signup'">sign up</button>
<button type="button" class="form-list" id="form-pomotodo" onclick="window.open('https://github.com/coqoa/POMOTODO/blob/main/README.md')">what is POMOTODO?</button>
</form>
</div>
</body>
</html>
login.js
//login.js
function printName(){
console.log('printName');
var loginForm = document.loginForm;
var loginId = loginForm.loginId.value;
var password = loginForm.loginPassword.value;
loginForm.submit();
}
4. server.js에서 '/loginPost'로 post요청을 받으면 어떻게 처리할지 작성해준다
미들웨어로 passport를 넣어줘서 요청과 응답사이에 인증을 하도록 한다
//server.js
app.post('/loginPost', passport.authenticate('local', { // 로컬방식으로 인증
failureRedirect : '/fail' ,
failureFlash : true
//실패시 /fail페이지로 이동시켜주세요
}), function(req, res){
req.session.save(function(){
// 성공시 redirect해서 홈페이지로 보내주기
res.redirect('/')
})
});
5. server.js 하단에 어떤식으로 인증할 지 작성해준다.
//server.js
//new LocalStrategy( { 설정 }, function(){ 아이디비번 검사하는 코드 } )
passport.use(new LocalStrategy({
usernameField: 'loginId', //사용자가 제출한 id가 어디 적혔는지(input의 name 속성값)
passwordField: 'loginPassword', //사용자가 제출한 pw가 어디 적혔는지(input의 name 속성값)
session: true, //로그인 후 세션을 저장할지 ?
passReqToCallback: false, //사용자가 입력한 id,pw외에 다른정보도 검증해보고 싶으면
}, function (inputId, inputPw, done) {
// console.log(inputId, inputPw) -> 사용자가 입력한 id/pw가 콘솔로그로 출력됨
db.collection('users').findOne({ id: inputId }, function (err, user) {
//입력한 id에 대한 정보를 결과에 담아옴
if (err) return done(err) //에러처리문법
if (!user) { //db에 없는 아이디일때?
return done(null, false, { message: 'ID does not exist' })
//done은 3개의 파라미터를 가질수 있음, 1: 서버에러, 2: 성공시 사용자db, 3:에러메시지
}
if(user){ // db에 아이디가 존재하면?
hasher({password:inputPw, salt: user.saltPassword}, function(err, pass, salt, hash){
// console.log(err, pass, salt, hash);
// err = undefined, pass:입력한비밀번호값, salt: 랜덤번호생성, hash: 입력비밀번호+salt값에 대한 해쉬값 을 출력해준다
// 입력비밀번호와 유저의 salt를 가져와서 hash로 만들고 그 해쉬값이 서버의 해쉬값과 일치하다면 로그인성공
if (hash == user.hashPassword) { // 인증완료 - 로그인
return done(null, user)
} else { // 비밀번호가 틀렸을 때
return done(null, false, { message: 'password incorrect' })
}
})
}
})
}));
* 적용되어있는 암호화는 따로 포스팅할예정
6. 세션을 만들고 세션아이디 발급해서 쿠키로 보내준다
//user 파라미터로 아이디/비밀번호 검증 결과가 들어간다
passport.serializeUser(function (user, done) {
done(null, user.id); // 세션데이터안에 passport의 user값으로 사용자의 아이디가 들어간다
});
// 세션데이터를 가진 사람을 db에서 찾아주는 코드
passport.deserializeUser(function(아이디, done) { //로그인하면 페이지에 방문할 때 마다 콜백함수가 호출, 사용자의 실제 데이터를 조회해서 가져옴
db.collection('users').findOne({ id: 아이디 }, function (err, result) {
done(null, result);
})
});
7. session이 있는사람과 없는사람을 구분해서 홈페이지를 호출해주기 위해 미들웨어를 만들고 적용한다
function homeLoginCheck(req, res, next) {
if (req.user) { //세션이 있으면 통과
next();
} else { //세션이 없으면 이런 페이지 생성
res.render('POMOTODO.ejs', { posts : 'log in', pomodoroRecord : ' ', todoListRecord : ' ', notTodoListRecord : ' ' });
}
}
app.get('/',homeLoginCheck,function(req, res){
// console.log('----get-req----');
// console.log(req.user.id);
// console.log('----get-req----');
// pomodoro 기록 출력하는 코드
db.collection('pomodoro').findOne({id:req.user.id}, function(err, pomodoroResult){
pomoResult = pomodoroResult.contentHTML;
db.collection('todolist').findOne({id : req.user.id}, function(err, todolistResult){
todoResult = todolistResult.todoListHTML;
db.collection('not-todolist').findOne({id : req.user.id}, function(err, nottodolistResult){
notTodoResult = nottodolistResult.notTodoListHTML;
//record컬렉션을 조회해서 없으면 만들어주는 코드
db.collection('pomodoro-record').findOne({ id: req.user.id, 'yyyymmdd' : yyyymmdd() }, function (err, pomoRecCheck) {
if(pomoRecCheck==null){
db.collection('pomodoro-record').insertOne({ 'id' : req.user.id, 'yyyymmdd' : yyyymmdd() ,'pomoRecord' : '' }, function(err, result){
console.log('db pomodoro-record create')
})
}
})
db.collection('todolist-record').findOne({ id: req.user.id, 'yyyymmdd' : yyyymmdd() }, function (err, todoRecCheck) {
if(todoRecCheck==null){
db.collection('todolist-record').insertOne({ 'id' : req.user.id, 'yyyymmdd' : yyyymmdd() ,'todoRecord' : '' }, function(err, result){
console.log('db todo-record create')
})
}
})
db.collection('not-todolist-record').findOne({ id: req.user.id, 'yyyymmdd' : yyyymmdd() }, function (err, notTodoRecCheck) {
if(notTodoRecCheck==null){
db.collection('not-todolist-record').insertOne({ 'id' : req.user.id, 'yyyymmdd' : yyyymmdd() ,'notTodoRecord' : '' }, function(err, result){
console.log('db not-todo-record create')
})
}
})
res.render('POMOTODO.ejs', { posts : req.user.id, pomodoroRecord : pomoResult, todoListRecord : todoResult, notTodoListRecord : notTodoResult});
})
})
})
});
'프로그래밍 > 개인프로젝트' 카테고리의 다른 글
POMOTODO : DB (0) | 2022.01.05 |
---|---|
POMOTODO : 암호화 (0) | 2022.01.05 |
POMOTODO : ejs템플릿 include 하기 (0) | 2022.01.05 |
POMOTODO : 회원가입 유효성검사 및 예외처리 (0) | 2022.01.05 |
POMOTODO(12) - 이슈발생 및 해결, 새롭게 구현한것 등등 (0) | 2022.01.04 |