socket.io + express-session + passport
hidden.in というsocket.ioを使ったビデオ会議をするプログラムを使用していました。
その際に、ユーザー名を表示させたいとの要望があり実装した備忘録です。
各バージョン
- Node v12.13.1
- express-session 1.17.1
- passport 0.4.1
- passport-local 1.0.0
hidden.inのインストール、使用方法については記事がありますので、参考にしてください。(また、後日まとめたいと思います)
インストール済みを想定して話を進めます。
少し話はそれますが、フォームにユーザー名を入力させてemitするといけるんちゃんと考え、実装したのですが、ブラウザをリロードすると消えてしまう為、ダメでした。
では、実装手順です
- express-sessionとpassportとpassport-localをinstallする
npm install i express-session passport passport-local
//インストール完了
2 requireして認証を実行する
var passport = require('passport');
var session = require('express-session');
var localStrategy = require('passport-local').Strategy;
var app = express();
var sessionMiddlewere = session({
resave:false,
saveUninitialized:false,
secret:'passport test',
cookie:{
httpOnly:false,
secure:false,
}
});
app.session = sessionMiddlewere;
app.use(sessionMiddlewere);
app.use(passport.initialize());
app.use(passport.session());
passport.use(new localStrategy({
usernameField:'username',
passwordField:'password',
passReqToCallback: true,
session:false,
},function(req,username,password,done){
process.nextTick(function(){
if(username === 'test' && password === 'test'){
return done(null,username);
}else{
console.log('Login Error');
return done(null,false,{message:'パスワードが正しくありません'});
}
})
}));
passport.serializeUser(function(user,done){
done(null,user);
});
passport.deserializeUser(function(user,done){
done(null,user);
});
var io = require('socket.io').listen(server);
io.use(function(socket,next){
sessionMiddlewere(socket.request,socket.request.res,next);
});
//詳細⬇️
今回はユーザー名testパスワードtestのみログインできるようにしています。
また、後半のio.useの部分のところでsocket.ioに対してsessionMiddlewereを使えるようにしていると思っています。
3 ルーティングの際にログイン済か認証する
app.get('/',sessionCheck);
function sessionCheck(req,res){
if(req.user){
res.render('index.ejs', {
title: 'Express',
user: req.user
});
}else{
res.redirect('/login');
}
}
app.get('/login',(req,res) => {
res.render('login.ejs',{
title:'Login Page',
user: req.user
});
});
app.post('/login',passport.authenticate('local',{
successRedirect:'/',
failureRedirect:'/login',
session:true,
}));
app.get('/logout',(req,res) => {
req.logOut();
res.redirect('/');
});
app.get("/:channel",(req,res) => {
if(req.user){
res.render('screen.ejs', {
title: 'Express',
user: req.user
});
}else{
res.redirect('/login');
}
});
ここでのポイントはログインをしていなかったら、/loginに飛ばす処理をしているのと、app.post(/login)のところで、ログイン判定をしてリダイレクトルートを決めているところだと思います。
4 login.ejsを作成する
!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= title %> </title>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" >
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<link rel='stylesheet' href='/css/style.css' />
</head>
<body>
<div class="container">
<h1>Login Page</h1>
<p class="lead">ログインページです</p><!-- /.lead -->
<br>
<form action="/login" method="post">
<div class="form-group">
<input type="text" name="username" id="username" placeholder="Enter UserName" class="form-control">
</div><!-- /.form-group -->
<div class="form-group">
<input type="password" name="password" id="password" class="form-control">
<button type="submit" class="btn btn-default">送信</button><!-- /.btn btn-default -->
<a href="/"><button class="btn btn-primary">キャンセル</button><!-- /.btn btn-primary --></a>
</div><!-- /.form-control -->
</form>
</div><!-- /.container -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" ></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
</body>
</html>
これでログインは実装できたのですが、サーバーサイド、クライアントサイドのsocket.ioでのセッション情報の取得の仕方は
io.sockets.on('connection', function (socket) {
console.log(socket.request.session.passport.user);
}
とすると認証されたユーザー情報が取得できるので、あとはこれをejsファイルで表示させてレイアウト整えるとユーザー名の表示の実装が出来る様になりました。
ユーザー名を表示させるプログラムについては、長くなったので別記事を用意したいと思います。
参考記事の皆様
node.js socket.io上でsessionを使う
Node.js+Express+Passport を使ってみた