[Node JS] socket.io/jwt認証/チャットメンバー情報のインポート


  • より前に、MongoDBを使用して会員登録すると、会員情報に基づくチャットが実現される.
  • 2userのメッセージ
  • が表示されます.
  • ユーザIDは、他のクライアントの
  • に表示する.

    ▼フルコード▼
    server.js
    const express = require('express');
    const app = express();
    app.use(express.static(__dirname + ''));
    
    const SocketIO = require('socket.io');
    
    // allows you to ejs view engine.
    app.set('view engine', 'ejs');  
    
    // importing body-parser to create bodyParser object
    const bodyParser = require('body-parser');
    // allows you to use req.body var when you use http post method.
    app.use(bodyParser.urlencoded({ extended: true }));
    
    // importing .env file
    require('dotenv').config();
    
    // Using jsonwebtoken module.
    const jwt = require("jsonwebtoken");
    
    const cookieParser = require('cookie-parser');
    app.use(cookieParser());
    
    // importing user schema.
    const User = require('./module/user');
    
    // importing auth function 
    const { auth } = require('./module/authMiddleware');
    
    // importing db function that connects with MongoDB.
    const { db } = require('./module/db');
    
    // importing bcrypt moudle to encrypt user password.
    const bcrypt = require('bcrypt');
    
    // declaring saltRounds to decide cost factor of salt function.
    const saltRounds = 10;
    
    //  To use python script
    var PythonShell = require('python-shell');
    
    // MongoDB user info DB
    db();
    
    const port = 8080;
    const server = app.listen(port, function() {
        console.log('Listening on '+port);
    });
    const io = SocketIO(server, {path: '/socket.io'});
    
    io
    .use((socket, next) => {
        cookieParser()(socket.request, socket.request.res || {}, next);
    })
    .on('connection', function (socket) {
        const req = socket.request;
        const decoded = jwt.verify(req.cookies.user, process.env.SECRET_KEY);
        socket.name = decoded.docs.id;
        console.log(socket.id, ' connected: ', socket.name);
        
        // broadcasting a entering message to everyone who is in the chatroom
        io.emit('msg', `${socket.name} has entered the chatroom.`);
    
        // message receives
        socket.on('msg', function (data) {
            console.log(socket.name,': ', data);
            // broadcasting a message to everyone except for the sender
            socket.broadcast.emit('msg', `${socket.name}: ${data}`);
        });
    
        // user connection lost
        socket.on('disconnect', function (data) {
            io.emit('msg', `${socket.name} has left the chatroom.`);
        });
    });
    
    app.get('/chat', auth, function(req, res) {
        const user = req.decoded;
        if(user) {
            const header = user.docs.id + "'s message";
            return res.render('chat', {header:header});
        } else {
            return res.sendFile(__dirname + '/chat.html');
        }
    });
    chat.ejs
    <h1 id="header"><%= header %></h1>
      <!-- importing JS file from socketIO server -->
      <script src="/socket.io/socket.io.js"></script>
      <!-- chat contents will be written down below. -->
      <div id="chatContent">
    
      </div>
      <input id="myChat" type="text">
      <input type="submit" id="send" value="Send">
      <form id="signOut">
        <button type="button" id="logOut" onclick="signOut()">Log out</button><br><br>
      </form>
                            
                            
    <script>
    	var socket = io.connect('http://localhost:8080', {
    		path: '/socket.io',
    		// transports: ['websocket']
        });
    
        // receiving a message
        socket.on('msg', function (data) {
    		var msgLine = $('<div class="msgLine">');
            var msgBox = $('<div class="msgBox">');
            msgBox.append(data);
            msgBox.css('display', 'inline-block');
            msgLine.append(msgBox);
            $('#chatContent').append(msgLine);
            // auto scorll down when a user send something
            chatContent.scrollTop = chatContent.scrollHeight;
        });
    
        // sending a message
        $("#myChat").on("keyup", function () {
            if (window.event.keyCode==13 && $(this).val()!="") {
                var msgLine = $('<div class="msgLine">');
                var msgBox = $('<div class="msgBox">');
                msgBox.append($(this).val());
                msgBox.css('display', 'inline-block');
                msgLine.css('text-align', 'right');
                msgLine.append(msgBox);
                $('#chatContent').append(msgLine);
                socket.emit('msg', $(this).val());
                $(this).val("");
                chatContent.scrollTop = chatContent.scrollHeight;
            }
        });
        function signOut() {
            $.ajax({
    	        type: "get",
    	        url: 'http://localhost:8080/logOut',
    	        data: {},
    	        dataType:'text',
    	        success: function(res) {
    	        location.reload();
    	        }
            });
    	}
    </script>
    <style>
    	* {
        	box-sizing: border-box;
    	}
        .msgLine {
    	    margin: 15px;
        }
        .msgBox {
            border: 1px solid black;
            background: black;
            padding: 2px 5px;
            border-radius: 10px;
        }
        #chatContent {
            border: 1px solid #000;
            width: 100%;
            height: 200px;
            margin-bottom: 10px;
            overflow-y: auto;
        }
        #myChat {
    	    width: 100%;
        }
        #msg, #myChat {
        	width: 80%;
    	    height: 32px;
    	    border-radius: 8px;
        }
        #send {
    	    width: 19%;
    	    height: 34px;
    	    border-radius: 50px;
    	    background: black;
    	    color: white;
        }
        #logOut {
    	    margin-top: 2%;
    	    width: 19%;
    	    height: 34px;
    	    border-radius: 50px;
    	    background: black;
    	    color: white;
        }
    </style>
    chat.html
    <form id="singin">
    	<h1>Sign in is required to enter a chatroom</h1>
    	<div class="field">
        	<label for="signinID">ID:</label>
    	    <input type="text" id="signinID" name="signinID" placeholder="Enter your fullname" /><br><br>
    	</div>
    	<div class="field">
        	<label for="signinPW">PW:</label>
    	    <input type="text" id="signinPW" name="signinPW" placeholder="Enter your password" /><br><br>
    	</div>
    	<button type="button" onclick="signInAjax()">Log in</button><br><br>
    </form>
    <script>
    	function signInAjax() {
    		const signinID = document.getElementById("signinID").value;
            const signinPW = document.getElementById("signinPW").value;
            document.getElementById("signinID").value = "";
            document.getElementById("signinPW").value = "";
            $.ajax({
            	type: "post",
    	        url: 'http://localhost:8080/login/:signInid/:signInpw',
    	        data: {id:signinID,pw:signinPW},
    	        dataType:'text',
    	        success: function(res) {
    		        location.reload();
    	        }
    		});
    	}
    </script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  • の上のホームページでは、Node JS: Messengerに入るとログインしたIDに基づいてネットチャットを実現できます.
  • は、前回作成したMongoDBおよびJWTを使用してログインします.
  • の下にあるNode JS: Messengerに入ると/chatの経路が表示され、ログインするとチャット画面が表示され、そうでなければログイン画面が表示される.

  • ▲非ログイン状態▲

    Fiveユーザー登録状態▲
    server.js/chatパスコード▼
  • (最上位レベルの完全なコードからモジュールへのコードコピー)
  • app.get('/chat', auth, function(req, res) {
        const user = req.decoded;
        if(user) {
            const header = user.docs.id + "'s message"; //ex) five's message
            return res.render('chat', {header:header});
        } else {
            return res.sendFile(__dirname + '/chat.html');
        }
    });
    auth関数▼
    const jwt = require('jsonwebtoken');
    const path = require('path');
    // importing .env file
    require('dotenv').config({ path: path.resolve(__dirname, '../.env') }); 
    
    exports.auth = (req, res, next) => {
        try {
            // verifying jwt using cookies and secret key then return it to req.decoded
            req.decoded = jwt.verify(req.cookies.user, process.env.SECRET_KEY);
            return next();
        }
        // autorized failed
        catch (error) {
            // Token has been expired
            if (error.name === 'TokenExpiredError') {
                console.log('auth TokenExpiredError');
                next();
                // return res.status(419).json({
                //     code: 419,
                //     message: 'Token has been expired.'
                // }); 
            }
            // JsonWebTokenError
            if (error.name === 'JsonWebTokenError') {
                console.log('JsonWebTokenError');
                next();
                // return res.status(401).json({
                //     code: 401,
                //     message: 'Invalid token.'
                // });
            }
        }
    }
    server.js内部socketIO
    const port = 8080;
    const server = app.listen(port, function() {
        console.log('Listening on '+port);
    });
    
    const io = SocketIO(server, {path: '/socket.io'});
    
    io
    .use((socket, next) => {
        cookieParser()(socket.request, socket.request.res || {}, next);
    })
    .on('connection', function (socket) {
        const req = socket.request;
        const decoded = jwt.verify(req.cookies.user, process.env.SECRET_KEY);
        socket.name = decoded.docs.id;
        console.log(socket.id, ' connected: ', socket.name);
        
        // broadcasting a entering message to everyone who is in the chatroom
        io.emit('msg', `${socket.name} has entered the chatroom.`);
    
        // message receives
        socket.on('msg', function (data) {
            console.log(socket.name,': ', data);
            // broadcasting a message to everyone except for the sender
            socket.broadcast.emit('msg', `${socket.name}: ${data}`);
        });
    
        // user connection lost
        socket.on('disconnect', function (data) {
            io.emit('msg', `${socket.name} has left the chatroom.`);
        }); 
    });
    ▼クライアントchat.ejs
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    
    <h1 id="header"><%= header %></h1>
    <!-- importing JS file from socketIO server -->
    <script src="/socket.io/socket.io.js"></script>
    <!-- chat contents will be written down below. -->
    <div id="chatContent">
    
    </div>
    <input id="myChat" type="text">
    <input type="submit" id="send" value="Send">
    <form id="signOut">
      <button type="button" id="logOut" onclick="signOut()">Log out</button><br><br>
    </form>
    <script>
    	var socket = io.connect('http://localhost:8080', {
    		path: '/socket.io',
    		// transports: ['websocket']
    	});
    
    	// receiving a message
    	socket.on('msg', function (data) {
    		var msgLine = $('<div class="msgLine">');
    		var msgBox = $('<div class="msgBox">');
    		msgBox.append(data);
    		msgBox.css('display', 'inline-block');
    		msgLine.append(msgBox);
    		chatContent').append(msgLine);
    		// auto scorll down when a user send something
    		chatContent.scrollTop = chatContent.scrollHeight;
    	});
    
    	// sending a message
    	$("#myChat").on("keyup", function () {
    		if (window.event.keyCode==13 && $(this).val()!="") {
    			var msgLine = $('<div class="msgLine">');
    			var msgBox = $('<div class="msgBox">');
    			msgBox.append($(this).val());
    			msgBox.css('display', 'inline-block');
    			msgLine.css('text-align', 'right');
    			msgLine.append(msgBox);
    			$('#chatContent').append(msgLine);
    			socket.emit('msg', $(this).val());
    			$(this).val("");
    			chatContent.scrollTop = chatContent.scrollHeight;
    		}
    	});
    	function signOut() {
    		$.ajax({
    			type: "get",
    				url: 'http://localhost:8080/logOut',
    				data: {},
    				dataType:'text',
    				success: function(res) {
    					location.reload();
    				}
    		});
    	}
    </script>
    <style>
    	* {
    		box-sizing: border-box;
    	}
    	.msgLine {
    		margin: 15px;
    	}
    	.msgBox {
    		border: 1px solid black;
    		background: black;
    		padding: 2px 5px;
    		border-radius: 10px;
    		}
    	#chatContent {
    		border: 1px solid #000;
    		width: 100%;
    		height: 200px;
    		margin-bottom: 10px;
    		overflow-y: auto;
    	}
    	#myChat {
    		width: 100%;
    	}
    	#msg, #myChat {
    		width: 80%;
    		height: 32px;
    		border-radius: 8px;
    	}
    	#send {
    		width: 19%;
    		height: 34px;
    		border-radius: 50px;
    		background: black;
    		color: white;
    	}
    	#logOut {
    		margin-top: 2%;
    		width: 19%;
    		height: 34px;
    		border-radius: 50px;
    		background: black;
    		color: white;
    	}
    </style>
    ▼結果▼
    jwtはブラウザのクッキーに格納されているので、2つのブラウザを使用してtwoおよびfiveでログインし、結果を表示できます.