처음부터 다시
1. 기본 세팅
$npm init
$npm i express nunjucks body-parser cookie cookie-parser (crypto 추후 추가)
server.js 와 파일 구조
views = index.html
<!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">
<title>Document</title>
<link rel ="stylesheet" href="./css/main.css">
<script type="text/javascript" src ="./js/main.js"></script>
</head>
<body>
<button id ="loginBtn">로그인</button>
<div class="layerPopup">
<div class="loginPopup">
<div id ="loginForm">
<h1>로그인 페이지</h1>
<input type="text" name="userid" id="userid" placeholder="아이디를 입력해주세요.">
<input type="password" name ="userpw" id="userpw" placeholder="패스워드를 입력해주세요">
<buton id = "localLogin" class="loginSubmit">로그인</buton>
<button id = "kakaoLogin" class="loginSubmit kakao">카카오로그인</button>
<p class="joinWord">
<span class="joinBtb">회원가입</span>
</p>
</div>
</div>
</div>
</body>
</html>
css, js 잘 연결되었는지 확인
-> layerPopup 안보이게 하고 또 다른 class 명 추가해서 open
.layerPopup{
display:none;
position:fixed;
top:0;
width:100%;
height:100%;
background:#000000a6;
}
.layerPopup.open{
display:block;
}
2. 처음 load 되었을 때 함수 init 실행되게 하기 -> 로그인 버튼 누르면 layerPopup 뜨게 하기
document.addEventListener('DOMContentLoaded', init);
function init(){
const loginBtn=document.querySelector('#loginBtn');
loginBtn.addEventListener('click',loginBtnFn);
}
function loginBtnFn(){
const layerPopup=document.querySelector('.layerPopup');
layerPopup.classList.add('open');
}
3. layerPopup 클릭하면 닫히게 만들기 (로그인 페이지를 눌렀을 때는 안닫히게)
방법 1 (방법2 추천)
function layerPopupClose(event){
const layerPopup = document.querySelector('.layerPopup')
const loginPopup=document.querySelector('.loginPopup')
console.log(event)
console.log(this)
if(event.target!=loginPopup){
layerPopup.classList.remove('open');
}
}
방법 2
function layerPopupClose(event){
console.log(event)
console.log(this)
if(event.target==this){
this.classList.remove('open');
}
}
4. 로그인 버튼 눌렀을 떄 서버에 fetch로 요청하기 BODY 방법 2가지
(현재 하고 있는 코드와는 별개) 질문 : form action body 보내는 것과 지금 버튼click event 로 보내는 방법 어떻게 다른지
이전까지 Req post로 보낼 때 form action='/login' 으로 하는 코드를 많이 썼는데 이번에 처음으로 click 해서 body를 보내보는 걸 함 . 그 차이점은 ↓↓↓
1. click event => 우리가 직접 http header body 작성
2, form tag 사용 => form이 자동으로 ( application:x-www-form-~ 요거 사용해서) body 내용 보내줌
BODY POST로 보내는 방법 2가지 중 첫번째 (직접 click event로 header,body 작성하는 방법 중 첫번째 )
main.js
document.addEventListener('DOMContentLoaded', init);
function init(){
const loginBtn=document.querySelector('#loginBtn');
loginBtn.addEventListener('click',loginBtnFn);
const layerPopup = document.querySelector('.layerPopup')
layerPopup.addEventListener('click',layerPopupClose);
const localLogin=document.querySelector('#localLogin');
localLogin.addEventListener('click',localLoginFn);
}
function loginBtnFn(){
const layerPopup=document.querySelector('.layerPopup');
layerPopup.classList.add('open');
}
function layerPopupClose(event){
if(event.target==this){
this.classList.remove('open');
}
}
async function localLoginFn(){
let userid = document.querySelector('#userid');
let userpw = document.querySelector('#userpw');
if(userid.value==''){
alert('아이디를 입력해주세요');
userid.focus();
return 0;
}
if(userpw.value==''){
alert('패스워드를 입력해주세요');
userpw.focus();
return 0;
}
let url = `http://localhost:3000/auth/local/login`
let options = {
method:'POST',
headers:{
'content-type':'application/x-www-form-urlencoded'
},
body:`userid=${userid.value}&userpw=${userpw.value}`,
}
let response = await fetch (url,options);
console.log(response);
}
/auth/local/login 부분 server.js에 추가 Post 니까 bodyPaser 다운, 코드 추가
$body-parser
server.js
const express=require('express');
//const cookieParser=require('cookie-parser');
const nunjucks =require('nunjucks');
const bodyParser=require('body-parser');
const app=express();
nunjucks.configure('views',{
express:app,
})
app.set('view engine', 'html');
app.use(bodyParser.urlencoded({extended:false}));
app.use(express.static('public'));
//app.use(cookieParser());
app.get('/', (req,res)=>{
res.render('index.html');
})
app.post('/auth/local/login',(req,res)=>{
let {userid,userpw} = req.body;
res.json({
result:true,
msg:'로그인 성공했습니다.'
})
})
app.listen(3000,()=>{
console.log('server start port: 3000');
})
응답 body 에 잘 담김
두번째 JSON으로 보내기 (보편적)
main.js
let url = `http://localhost:3000/auth/local/login`
let options = {
method:'POST',
headers:{
'content-type':'application/json'
},
body:JSON.stringify({
userid:userid.value,
userpw:userpw.value,
})
}
let response = await fetch (url,options);
console.log(response);
content-type: applicaition/json이면 -> body: JSON.stringfy({}) 로 !
터미널 console.log = undefined -> 미들웨어 app.user(Parser.json()); 을 놔서 json 을 받을 수 있게 만들기
app.use(bodyParser.json());
요코드 하나만 넣으면 server on -> console.log잘 찍힘
첫번째 방법 : QueryString 으로 보냄 'content-type' : 'application/x-www-form-urlencoded'
두번째 방법: Json 으로 보냄 'content-type': 'application/json'
- bodyParsor.json() 필요
EXTRA ) JSON 형태로 보낼 때 body말고 header에다가 넣기 (요구에 따라 이런 경우도 있다고 한다)
main.js
let url = `http://localhost:3000/auth/local/login`
let options = {
method:'POST',
headers:{
'content-type':'application/json',
'data':JSON.stringify({
userid:userid.value,
userpw:userpw.value,
})
},
}
let response = await fetch (url,options);
console.log(response);
server.js
app.post('/auth/local/login',(req,res)=>{
let {userid,userpw} = JSON.parse(req.get('data'));
console.log(userid,userpw)
res.json({
result:true,
msg:'로그인 성공했습니다.'
})
})
body로 보낼 때는 app.post받을 때 JSON을 안써줬어도 되었다 (server.js 에 app.use(bodyParser()) 가 있어서 그런 것 같다. 여기서는 body로 보낸게 아니고 headers에 넣은거라 JSON.stringify 를 써서 json으로 보낸걸 받을 때 JSON.parse로 파싱함 req.query or req.body 가 아니고 --> req.get('data') 'data'라는 key값에 담긴걸 get 하겠다는 의미같음
-> 다시 post로 돌려놓기
지금까지 로그인 누르면 아이디,비번이 vs터미널에 나오게 만듬
DB는 아직 연결 x 먼저
5. 로그인 성공여부 만들기
server.js
app.post('/auth/local/login',(req,res)=>{
let {userid,userpw} = req.body;
console.log('body req : ' ,userid, userpw)
let result = {
result:false,
msg:'아이디와 패스워드를 확인해주세요'
}
if(userid =='root'&&userpw=='root'){
result = {
result:true,
msg:'로그인 성공 '
}
}
res.json(result)
})
main.js
let response = await fetch (url,options);
let res_result = await response.json();
console.log(res_result);
6. 로그인 성공 시 token 생성하기
.$npm i crypto dotenv
.env 파일 생성, salt라는 변수에 아무string 적기 (암호)
salt=asdfasdf
jwt.js 파일 생성, 코드 작성 -> console.log에 찍힌 token값 JWT 사이트가서 확인 if verified -> module exports
require('dotenv').config();
const crypto = require('crypto');
//JWT 토큰 header.payload.signature
function createToken(userid) {
let header = { "tpy": "JWT", "alg": "HS256", }
//현재시간으로부터 미래시간 : 2시간을 더한 수
//두시간 뒤 재로그인 - 길면 길수록 해킹 위험 up
let exp = new Date().getTime() + ((60 * 60 * 2) * 1000) //1970.1.1부터 0 // 1월1일 1초지났으면 1000
let payload = {
//인자로 들어온 애
userid,
//expiary date
exp,
}
///Buffer.from - 바이너리 파일 만들기
const encodingHeader = Buffer.from(JSON.stringify(header))
.toString('base64')
.replace('==', '').replace('=', '');
const encodingPayload = Buffer.from(JSON.stringify(payload))
.toString('base64')
.replace('==', '').replace('=', '');
//console.log(encodingHeader, encodingPayload);
//암호화 시작 //첫번째 : 암호방식 /두번째인자 : key값 (이게 공개되면 해킹됨) - best-env
let signature = crypto.createHmac('sha256', Buffer.from(process.env.salt))
.update(encodingHeader + "." + encodingPayload)
.digest('base64')
.replace('==', '').replace('=', '');
let jwt = `${encodingHeader}.${encodingPayload}.${signature}` return jwt;
}
let token = createToken('asdf');
console.log(token)
//userid 값만 넣어줄 예정
//module.exports=(userid)=>{ } 아래와 같은 뜻
module.exports = createToken;
server.js에서 JWT 토큰 키 가져오기
const tokenKey=require('./jwt')
server.js 전체
const express=require('express');
//const cookieParser=require('cookie-parser');
const nunjucks =require('nunjucks');
const bodyParser=require('body-parser');
const tokenKey=require('./jwt')
const app=express();
nunjucks.configure('views',{
express:app,
})
app.set('view engine', 'html');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:false}));
app.use(express.static('public'));
//app.use(cookieParser());
app.get('/', (req,res)=>{
res.render('index.html');
})
app.post('/auth/local/login',(req,res)=>{
let {userid,userpw} = req.body;
console.log('body req : ' ,userid, userpw)
//원래는 db접속 후 결과 리턴
let result = {};
if(userid =='asdf'&&userpw=='asdf'){
result = {
result:true,
msg:'로그인 성공 '
}
let token = tokenKey(userid)
res.cookie('accessToken', token, {httpOnly:true, secure:true,});
}else{
result={
result:false,msg:'아이디와 패스워드를 확인해주세요'
}
}
res.json(result)
})
app.listen(3000,()=>{
console.log('server start port: 3000');
})
7. TOKEN검증 (생성된 token과 내가 만든 token 이 일치하는지)
middleware 폴더 생성 -> auth.js 파일 생성, 코드 작성
require('dotenv').config();
const crypto = require('crypto');
const tokenKey=require('../jwt');
let accessToken = tokenKey('asdf');
console.log(accessToken)
console.log 찍기 ** 주의 폴더 안에 server이기 때문에 폴더 경로까지 쓰기
node .\middleware\auth.js
console창에 key 뜨는거 확인
jwt.js 에서 만든 token 값이 잘 넘겨왔는지 확인했으면 받은 token값을 .을 기준으로 split, 배열에 담기
let accessToken = tokenKey('asdf');
let accessToken_arr=accessToken.split('.');
let header = accessToken_arr[0];
let payload = accessToken_arr[1];
변수 여러개 한번에 담기↓↓
require('dotenv').config();
const crypto = require('crypto');
const tokenKey=require('../jwt');
let accessToken = tokenKey('asdf');
let [header, payload, signature]=accessToken.split('.');
검증 / 실패 만들기
require('dotenv').config();
const crypto = require('crypto');
const tokenKey=require('../jwt');
let accessToken = tokenKey('asdf');
let [header, payload, signature]=accessToken.split('.');
let signatureToCheck = signatureCheck(); 질문 1/ 인자값 꼭 있어야하는지-> ㄴㄴ! 2. fn 없애기가능?
if(signature==signatureToCheck){
console.log('검증')
}else{
console.log('실패')
}
function signatureCheck(){
const signatureChecked = crypto.createHmac('sha256',Buffer.from(process.env.salt))
.update(header+'.'+payload)
.digest('base64')
.replace('==','=').replace('=','');
return signatureChecked
}
8. TOKEN 원래의 형태로 다시 복원하기
JS에 복원함수 있음 -> JSON.parse( Buffer.from(payload, 'base64') ~
payloade 안에 userid, exp 가 있어서 payload를 바꿔서 안에 있는 userid,exp 값 변수에 담기
require('dotenv').config();
const crypto = require('crypto');
const tokenKey=require('../jwt');
let accessToken = tokenKey('asdf');
let [header, payload, signature]=accessToken.split('.');
let signatureToCheck = signatureCheck(header,payload);
function signatureCheck(){
const signatureChecked = crypto.createHmac('sha256',Buffer.from(process.env.salt))
.update(header+'.'+payload)
.digest('base64')
.replace('==','=').replace('=','');
return signatureChecked
}
if(signature==signatureToCheck){
console.log('검증')
let {userid,exp}=JSON.parse(Buffer.from(payload,'base64').toString());
console.log(userid, exp)
req.userid = userid;
}else{
console.log('실패')
}
9. token 생성 이후 2시간 지났는지 if 조건문 만들기
if (signature == signatureToCheck) {
console.log('검증')
let { userid, exp } = JSON.parse(Buffer.from(payload, 'base64').toString());
console.log(userid, exp)
let newExp = new Date().getTime();
if (newExp > exp) {
console.log('토큰 만료');
redirect('/msg=토큰만료')
return 0; //안써주면 안되더라구..
}
req.userid=userid; // 질문
next(); //질문ok next() ? 여기에 쓴 이유 아래 더이상 실행할게 없는데
//module.exports 되고 그 뒤에 명령 계속 실행해라 ~ 같음 (in server.js-/auth/local/login)
} else {
console.log('실패')
res.redirect('/msg=해킹이다')
}
10. exports 하기 ->userid 사용하려면 middleware 통해 사용
질문 : module.exports를 끝에 한 줄로 쓰기 ?
auth.js
module.exports할 때 언제는 맨 밑에 쓰고 언제는 요렇게 =()=>{}ㄴ
하나만 쓸 때는 아래처럼 한번에 처리
두개 이상이면 아래다가 쓰는 편이 좋음 (아래 예시 有)
require('dotenv').config();
const crypto = require('crypto');
const tokenKey = require('../jwt');
module.exports = (req, res, next) => { 질문 // 어쩔떄는 맨 아래 exports / 여기는 조금 다른 이유?
let accessToken = tokenKey('asdf');
let [header, payload, signature] = accessToken.split('.');
let signatureToCheck = signatureCheck(header, payload);
function signatureCheck() {
const signatureChecked = crypto.createHmac('sha256', Buffer.from(process.env.salt))
.update(header + '.' + payload)
.digest('base64')
.replace('==', '=').replace('=', '');
return signatureChecked
}
if (signature == signatureToCheck) {
console.log('검증')
let { userid, exp } = JSON.parse(Buffer.from(payload, 'base64').toString());
//질문 - 위의 코드 toString('base64')와 어떻게 다른지
console.log(userid, exp)
let newExp = new Date().getTime();
if (newExp > exp) {
console.log('토큰 만료');
redirect('/msg=토큰만료')
return 0;
}
req.userid=userid;
next();
} else {
console.log('실패')
res.redirect('/msg=해킹이다')
}
}
위에 module.exports(req,res,next)=>{전체 내용} 요방법도 있고 아래처럼 aa 라는 이름의 function을 exports 해도됨
require('dotenv').config();
const crypto = require('crypto');
const tokenKey = require('../jwt');
function aa (req, res, next) { 질문 // 어쩔떄는 맨 아래 exports / 여기는 조금 다른 이유?
let accessToken = tokenKey('asdf');
let [header, payload, signature] = accessToken.split('.');
let signatureToCheck = signatureCheck(header, payload);
function signatureCheck() {
const signatureChecked = crypto.createHmac('sha256', Buffer.from(process.env.salt))
.update(header + '.' + payload)
.digest('base64')
.replace('==', '=').replace('=', '');
return signatureChecked
}
if (signature == signatureToCheck) {
console.log('검증')
let { userid, exp } = JSON.parse(Buffer.from(payload, 'base64').toString());
//질문 - 위의 코드 toString('base64')와 어떻게 다른지
console.log(userid, exp)
let newExp = new Date().getTime();
if (newExp > exp) {
console.log('토큰 만료');
redirect('/msg=토큰만료')
return 0;
}
req.userid=userid;
next();
} else {
console.log('실패')
res.redirect('/msg=해킹이다')
}
}
module.exports=aa;
위 질문 답변 : let { userid, exp } = JSON.parse(Buffer.from(payload, 'base64').toString());
//질문 - 위의 코드 toString('base64')와 어떻게 다른지
// JWT 토큰 값 = accessToken (base64)로이미 변환된 글자
payload = base64 로 변환되어 있음 .toString() 원래 글자로 바꾼다. (디코딩) string을 객체로 바꿈
그럼 저기 (payload,'base64').toString() toSTring --> base64로 되어있는 문자열을--> b** console.log쳐보기
2 -> 16진수 연동잘됨
16 -> 64진수 변환 쉽다
64진수 좋은 점
10진수 ex) 10 == 0010 4칸 사용
16진수 ex) 10 == A 1칸 사용
64진수 -> 10진수의 글자들을 또 함축 가능
=>변환쉽고, 글자수도 줄여져서 , 특히 대량일 때.
JSON.parse -> json 객체로 바꿔주는거
일반 stirng -> base64 - 인코딩
base63 -> stirng - 디코딩
암호화, 복호화 방법, 순서 ↓↓
https://blckchainetc.tistory.com/207
server.js 미들웨어 auth 가져오기
const auth = require('./middleware/auth')
index.html 회원정보 a 추가
<button id ="loginBtn">로그인</button>
<a href="/user/info">회원정보 보기</a>
server.js 에 /user/info 추가
app.get('/user/info',auth,(req,res)=>{
let userid = req.userid;
res.send(`user info 입니다 hello${userid}`)
})
'블록체인 기반 핀테크 및 응용 SW개발자 양성과정 일기' 카테고리의 다른 글
[54일차]20210531 WebSocket, 웹소켓 연결하기 connection, connect, send, call / Javascript , node.js (1) | 2021.05.31 |
---|---|
[JavaScript / Node.js] sha256 해시 알고리즘 암호화, 검증, 복호화 JWT 토큰 사용 정리 (1) | 2021.05.31 |
[53일차] 20210528 JWT token 암호화 , 검증 예제 Node.js (6) | 2021.05.28 |
[52일차 복습] Javascript node.js [JWT] token 토큰 암호화해서 브라우저 cookie에 저장하기 (0) | 2021.05.27 |
[52일차]20210527 JWT token 토큰 만들어 브라우저 cookie에 저장하기 (0) | 2021.05.27 |