로그인을 한 사람에게만 채팅가능하도록 만들기
-> 미들웨어 auth.js - 토큰값없을 경우 저 버튼이 실행되지 않도록
server.js - auth 추가
app.get('/chat',auth, (req,res)=>{
res.render('chat.html')
})
server on -> check -> consol -> '로그인을 진행해주세요'
auth.js
json 타입으로 값을 넘겨주고 싶음/ 어떻게 안되었는지 text를 보내기
if(AccessToken == undefined){
console.log('로그인을 진행해주세요')
//res.redirect('/?msg=로그인을 진행해주세요')
res.json({result:false, msg:'로그인이 필요합니다'})
return
}
저 json은 객체처럼 생겼어도 스트링으로 보내는 것 (교환하는 값은 무조건 TEXT)
express가 알아서 json을 스트링으로 변환시켜서 보냄
chat.js
chatBtn.addEventListener('click',async ()=>{
let url = 'http://localhost:3000/chat'
let options = {
method:'GET'
}
let response = await fetch (url,options);
let result = await response.text();
console.log(response);
console.log(result);
chatRoom.innerHTML=result;
})
설명 :
response.json() - body에 있는 string 값 바로 스트링으로 가져다 쓸 떄.
response.text() - body에 있는 내용을 있는 그대로 받을 때 (날 것 그 대ㅐ로) (위의 사진)
result 값이 실패 시에는 -> json 형태
성공할 때는 html - text형태로 온다.
* json 타입인가 아닌가를 찾는 함수 만들기 == 성공했나 실패했나
text---> json 형태로 바꾸는 법 - JSON.parse()
json---> text : JSON.stringify()
chat.js
const chatBtn=document.querySelector('#chatBtn');
const chatRoom = document.querySelector('#chatRoom');
chatBtn.addEventListener('click',async ()=>{
let url = 'http://localhost:3000/chat'
let options = {
method:'GET'
}
let response = await fetch (url,options);
let result = await response.text();
if(isJson(result)){
//로그인처리 잘 안되었을 때(json일 떄 from auth) => True
let json = JSON.parse(result);
if(json.result == false) alert(json.msg);
return
}else{
//로그인처리 완료되었을 때 => False
chatRoom.innerHTML=result;
}
})
function isJson(str){
//Ture or False 값만 나오게
try{
let json = JSON.parse(str)
return (typeof json == 'object') //맞으면 True,틀리면 False
}catch(e){
//str= 'adsfsafdasdf' 경우 try 문을 실행할 수 없음
//json으로 변환할 수 업성서
return false;
}
}
function isJson에서 chatBtn을 click했을때 fetch('/chat')으로 얻은 값이 function isJson을 통해 객체로 판정되면 (보내준게 html 이 아니기 때문에- 로그인 실패 ) 라면 return : True / true 라면 받은 string 값을 JSON으로 바꿔서 그 안의 result 값이 false 라면 보내온 msg에 있는 값을 alert 해라
똑같은 아래 두 코드
if(json.result == false) alert(json.msg);
if(!json.result) alert(json.msg);
여기까지 server on -> check
auth.js
res.json으로 수정 / token 삭제 추가
if(sign != signature){
console.log('부적절한 토큰')
//res.redirect('/?msg=부적절한 토큰')
res.clearCookie('AccessToken')
res.json({result:false,msg:'부적절한 토큰입니다.'})
return
}
let {userid,exp} = JSON.parse(Buffer.from(payload,'base64').toString())
let nexttime = new Date().getTime();
if(nexttime > exp){
console.log('토큰 만료')
res.clearCookie('AccessToken')
//res.redirect('/?msg=토큰만료')
res.json({result:false,msg:'토큰만료'})
return
}
server on -> 로그인 -> network - application 쿠키 토큰값 생김 -> 채팅 눌러보기
쿠키 내용 봐봐 (in application) -> 쿠키 내용을 임의로 바꾸면 -> 로그인이 되지 않아야해 ==로그인이 안된상태랑 똒같이 처리해야함
토큰 값을 바꾸고 다시 '채팅' 을 누르면
이렇게됨.
누군가 악의적으로 토큰값 수정하면 로그인 안되게 처리함 by예전에 작업한 요 코드
채팅 한번 click하면 닫히는거 처리해보기
-> 로그인창과 다르게 해볼꺼야
chat.js
flag = undefined; 선언 / 새로운 함수 만들어서 addEvent 내용 붙여넣기 /
flat의 값에 따라 (구분값)
let flag = undefined;
chatBtn.addEventListener('click', ()=>{
switch(flag){
case true:
//열린 상태에서 다시 누를 때 -> 닫히는 기능할 때
//flag = false;
chatRoom.style.display='none';
break;
case false:
//처음 제외하고 다시 열릴 때
//flag = true;
chatRoom.style.display='block';
break;
case undefined:
//처음으로 이 버튼을 눌렀을 때
//flag = true;
getChatRoom()
break;
}
})
async function getChatRoom(){
let url = 'http://localhost:3000/chat'
let options = {
method:'GET'
}
let response = await fetch (url,options);
let result = await response.text();
if(isJson(result)){
//로그인처리 잘 안되었을 때(json일 떄 from auth) => True
//isJson
let json = JSON.parse(result);
if(json.result == false) alert(json.msg);
return
}else{
//로그인처리 완료되었을 때 => False
chatRoom.innerHTML=result;
}
}
server on - check
채팅을 누르면 req 가 계속 늘어남 -> 이런 식은 좋지않음 -> 그래서 한번만 가져와서 style none, block 으로 만든 것
fetch 라는 것은url 변경과 같음 (req와 res 가 일어남) 요 요청을 계속 채팅 클릭할 떄마다 생기게하면 안좋으닝아래 처럼 ㄱ ㄱ
** 아주 중요한 개념
chatBtn.addEventListener('click', ()=>{
switch(flag){
case true:
//열린 상태에서 다시 누를 때 -> 닫히는 기능할 때
flag = false;
chatRoom.style.display='none';
break;
case false:
//처음 제외하고 다시 열릴 때
flag = true;
chatRoom.style.display='block';
break;
case undefined:
//처음으로 이 버튼을 눌렀을 때
flag = true;
getChatRoom()
break;
}
})
요렇게 하면 req가 딱 한번 (맨 처음) 일어남. - 서버의 리소스 낭비 줄임
css 입혀보기
css - chat.css 파일 만들기
index.html 에 연결
<title>INDEX.html</title>
<script type="text/javascript" src="/js/main.js"></script>
<link href="/css/main.css" rel="stylesheet">
<link href="/css/chat.css" rel="stylesheet">
</head>
chat.html <div> 추가
<div id="chat">
<div>
<span class="me">안녕하세요</span>
<!--내가 쓴글-->
</div>
<div>
<span class="you"> 네 안녕 </span>
<!--남이 쓴글-->
</div>
</div>
<div id="chatInputArea">
<input type="text" id="msg">
<button id="chatSend">전송</button>
</div>
public - css - chat.css
#chat{
width:400px;
height:600px;
background:wheat;
}
#chat>div>span{
display:inline-block;
padding:7px 14px;
border-radius:15px;
}
#chat>div{
height:30px;
padding:5px;
}
#chat>div>span.me{
float:left;
background-color: yellow;
}
#chat>div>span.you{
float:right;
background-color: white;
}
#chatInputArea{
width:400px;
padding:5px 7px;
}
#chatInputArea>input{
width:200px;
padding:7px 14px;
border:1px solid 999999;
}
#chatInputArea>button{
padding:7px 14px;
background-color: #eee;
border:1px solid #999999;
}
교수님의 CSS KNOW-HOW
333333 찐함
666666
999999 연함
eeeeee
efefef
dddddd
ededed
쏘켓타임
$npm i socket.io http
server.js 에 가져오는 코드 / 설정 코드 작성 / app -> server.listen 으로 수정
const socket = require('socket.io');
const http = require('http');
const server = http.createServer(app);
const io = socket(server);
.
.
.
server.listen(3000,()=>{
console.log('server start port: 3000');
})
client 쪽에도 연결하기
index.html
<script type="text/javascript" src="/socket.io/socket.io.js"></script>
위의 코드가 실행안되면 저번처럼 node_modules 에 접착해야함.
될 때도, 안될 때도 있다고 함 - 그 이유는 미지수,,
저 코드만으로 잘 연결 되었다.
최초의 요청, 응답 : Handshake
Client ---------REQ (쿠키) -------> Server
쿠키도 같이 보내줘서 server가 쿠키 사용할 수 있음.
server.js
io.sockets.on('connection',socket=>{
console.log(socket.handshake);
})
진짜 socket안에 handshake가 있네,,
chat.js
const socket = io();
-
return
}else{
//로그인처리 완료되었을 때 => False
chatRoom.innerHTML=result;
socketChat()
}
}
function socketChat(){
socket.on('connect',()=>{})
}
-
코드를 따로 뺐다. 보기 쉽게 / 넣은 위치는 로그인 잘 완료 되었으 때
server on -> check
101 잘 떳는지췤
console.log(socket.handshake)
{
headers: {
host: 'localhost:3000',
connection: 'keep-alive',
'sec-ch-ua': '" Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"',
accept: '*/*',
'sec-ch-ua-mobile': '?0',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36',
'sec-fetch-site': 'same-origin',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
referer: 'http://localhost:3000/',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7',
cookie: 'AccessToken=eyJ0cHkiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyaWQiOiJhc2RmIiwiZXhwIjoxNjIyNjA1MTQ2NzcxfQ.j2TjcoW5kWpM5achLpaI91WFV0Gx0hqAkg%2Bu2CvrEjo'
},
time: 'Wed Jun 02 2021 11:29:58 GMT+0900 (대한민국 표준시)',
address: '::1',
xdomain: false,
secure: false,
issued: 1622600998018,
url: '/socket.io/?EIO=4&transport=polling&t=NdAZbnS',
query: [Object: null prototype] {
EIO: '4',
transport: 'polling',
t: 'NdAZbnS'
},
auth: {}
}
req.에 접근해야 user의 정보를 알 수 있음.
우리는 지금 그 바깥에서 작업한거라 user id 값을 알 수 없음
handshake 안에 Cookie 값이 있음 ( 요 안에 AccessToken 값이 있음) - 어딘가에 숨겨져있고 복구화를 ㅎㅐ야한다.
AccessToken 값 = 그냥 STRING -> 복구화 (id값이 있는 payload 필요)
- 해당 값을 .로 split해서 payload 가져오기
실제로 cookie값 안에는 로그인값 / 장바구니 / 등 쿠키가 여러개일 것이다라고 생각하고 작업하기
임시로 생성하기 -> network 가서 그냥 만들어
더블클릭으로 변경할 수 있는데 안되어서 아래 console.log로 추가해줌
server.js
io.sockets.on('connection',socket=>{
console.log(socket.handshake.headers.cookie);
})
server on -> check
console
AccessToken=eyJ0cHkiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyaWQiOiJhc2RmIiwiZXhwIjoxNjIyNjA1MTQ2NzcxfQ.j2TjcoW5kWpM5achLpaI91WFV0Gx0hqAkg%2Bu2CvrEjo; user=hh
cookie 지금 2개 들어 있음
cookie는 ; 를 기준으로 나뉘어져 있음
cookie.js 만들어서 node cookie.js 명령어 실행으로 결과값 바로바로 확인해보기
let cookie = 'AccessToken=eyJ0cHkiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyaWQiOiJhc2RmIiwiZXhwIjoxNjIyNjA1MTQ2NzcxfQ.j2TjcoW5kWpM5achLpaI91WFV0Gx0hqAkg%2Bu2CvrEjo; user=hh'
let cookieArr = cookie.split(';');
cookieArr.forEach(v=>{
let [name,value] = v.split('=');
if(name.trim() == 'AccessToken'){
console.log(value);
//이제 Accesstoken에서 payload 값 가져오기
let jwt = value.split('.');
//payload: jwt[1] 이제 복구화 진행
console.log(jwt[0])
console.log(jwt[1])
console.log(jwt[2])
let payload = Buffer.from(jwt[1],'base64').toStirng();
console.log(payload);
let obj = JSON.parse(payload);
console.log(obj.userid);
}
})
forEach 대신 filter, map으로도 가능하다
let cookie = 'AccessToken=eyJ0cHkiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyaWQiOiJhc2RmIiwiZXhwIjoxNjIyNjA1MTQ2NzcxfQ.j2TjcoW5kWpM5achLpaI91WFV0Gx0hqAkg%2Bu2CvrEjo; user=hh'
let cookieArr = cookie.split(';');
cookieArr.forEach(v=>{
let [name,value] = v.split('=');
if(name.trim() == 'AccessToken'){
let jwt = value.split('.');
let payload = Buffer.from(jwt[1],'base64').toString();
let {userid} = JSON.parse(payload);
console.log('첫번째방법 : ',userid);
}
})
let userid1 = cookie.split(';').filter(x => x.indexOf('AccessToken')==0)
.map(v=>{
let [name,value]=v.trim().split('=');
return JSON.parse(Buffer.from(value.split('.')[1], 'base64').toString()).userid;
})
console.log('두번째방법 : ', userid1)
요렇게,,
server.js 로 옮기기
let id;
io.sockets.on('connection', socket => {
let cookieString = socket.handshake.headers.cookie;
let cookieArr = cookieString.split(';');
cookieArr.forEach(v => {
let [name, value] = v.split('=');
if (name.trim() == 'AccessToken') {
let jwt = value.split('.');
let payload = Buffer.from(jwt[1], 'base64').toString();
let {userid} = JSON.parse(payload);
id = userid;
}
})
console.log('cc',id);
})
- if 추가
let id;
io.sockets.on('connection', socket => {
let cookieString = socket.handshake.headers.cookie;
console.log(cookieString)
if (cookieString != undefined) {//쿠키값이 없을 떈 실행하지 않겠다.
let cookieArr = cookieString.split(';');
cookieArr.forEach(v => {
let [name, value] = v.split('=');
if (name.trim() == 'AccessToken') {
let jwt = value.split('.');
let payload = Buffer.from(jwt[1], 'base64').toString();
let { userid } = JSON.parse(payload);
id = userid;
}
})
console.log(id);
}
})
-> 크롬, 파이어폭스 두개 켜서 로그인 다른 아이디로 들어가서 console.log 를 확인 -> 각각의 id가 뜬다.
가능한 이유 : handshake 요청되었을 때 각각 Clients들의 req with cookie을 해석해서 보여준 것이기 때문에
chat.js 에서 event를 등록할 수가 없다.
이렇게 chat.html 의 id 값을 chat.js 에 가져올 수가 없다.
파일이 처음 로드가 되었을 때 chat.js 가 실행 -> chat.html 은 그 때 없음.
-> 가장 간단한 방법 : chat.html에 직접 event를 줌 - onclick="send()"
chat.html
<div id="chat">
<div>
<span class="me">안녕하세요</span>
<!--내가 쓴글-->
</div>
<div>
<span class="you"> 네 안녕 </span>
<!--남이 쓴글-->
</div>
</div>
<div id="chatInputArea">
<input type="text" id="msg">
<button id="chatSend" onclick="send()">전송</button>
</div>
chat.js
function send(){
const msg = document.querySelector('#msg');
console.log(msg.value);
}
브라우저 console.log 확인
내용 보내기 코드
chat.js
function send(){
const msg = document.querySelector('#msg');
console.log(msg.value);
socket.emit('send', msg.value);
}
server.html -connection 안에
let id;
io.sockets.on('connection', socket => {
let cookieString = socket.handshake.headers.cookie;
if (cookieString != undefined) {//쿠키값이 없을 떈 실행하지 않겠다.
let cookieArr = cookieString.split(';');
cookieArr.forEach(v => {
let [name, value] = v.split('=');
if (name.trim() == 'AccessToken') {
let jwt = value.split('.');
let payload = Buffer.from(jwt[1], 'base64').toString();
let { userid } = JSON.parse(payload);
id = userid;
}
})
console.log(id);
}
socket.on('send', data=>{
console.log(data)
socket.broadcast.emit('msg',data)
})
})
chat.js
function send(){
const msg = document.querySelector('#msg');
console.log(msg.value);
socket.emit('send', msg.value);
addCard(msg.value, 'me');
}
//type = me or you
function addCard(text, type){
const div = document.createElement('div');
const span = document.createElement('span');
const chat = document.querySelector('#chat');
span.innerHTML = text;
span.classList.add(type);
div.appendChild(span);
chat.appendChild(div)
}
server on -check
chat.js
function socketChat(){
socket.on('connect',()=>{});
socket.on('msg', data=>{
addCard(data,'you')
})
}
카카오 메세지 받으면 읽음 처리
chat.js - >socket -> 에서 우리의 현 상태 (읽었는지) 를 파악하는걸 만들기
아까 한 flag 값 사용
dataset
html 의 data-value="" -> 요게 dataset 해당 element에 어떤 값을 가지고 있는가 저장할 떄
index.html - button에 data-value를 자바스크립트로 만들어서 수가 올라가도록
chat.js
function socketChat(){
socket.on('connect',()=>{});
socket.on('msg', data=>{
//html tag로 data-value 를 의미 == dataset.value
chatBtn.dataset.value=1;
if(flag==false){
}else{
}
addCard(data,'you')
})
}
보낸 사람말고 받은 사람만 value가 1 ; 이제 이걸 늘어나게 만들기
chat.js
function socketChat(){
socket.on('connect',()=>{});
socket.on('msg', data=>{
//html tag로 data-value 를 의미 == dataset.value
chatBtn.dataset.value= chatBtn.dataset.value+1;
if(flag==false){
}else{
}
addCard(data,'you')
})
}
int 가 아니여서 111 이렇게 됨
index.html
<button id = "chatBtn" data-value="0">채팅</button>
chat.js
function socketChat(){
socket.on('connect',()=>{});
socket.on('msg', data=>{
//html tag로 data-value 를 의미 == dataset.value
chatBtn.dataset.value= parseInt(chatBtn.dataset.value)+1;
if(flag==false){
}else{
}
addCard(data,'you')
})
}
이제 채팅 버튼에 요 숫자를 표현하기
function socketChat(){
socket.on('connect',()=>{});
socket.on('msg', data=>{
//html tag로 data-value 를 의미 == dataset.value
chatBtn.dataset.value= parseInt(chatBtn.dataset.value)+1;
if(flag==false){
chatBtn.innerHTML=`채팅<span style="coler:red; padding:20px;">${chatBtn.dataset.value}</span>`
}else{
}
addCard(data,'you')
})
}
chat.js
chatBtn.addEventListener('click', ()=>{
switch(flag){
case true:
//열린 상태에서 다시 누를 때 -> 닫히는 기능할 때
flag = false;
chatRoom.style.display='none';
break;
case false:
//처음 제외하고 다시 열릴 때
flag = true;
chatBtn.innerHTML='채팅';
chatBtn.dataset.value=0;
chatRoom.style.display='block';
break;
여기까지 하면 채팅 버튼 클릭해서 보면 해당 count 값은 없어짐
오늘의 수업 끝,,,,
id 채팅창에 나오도록 ,,
jwt 인증 토큰으로 구현하기