socket.io にセッション情報を渡す

# socket.io + express-session + passport
[hidden.in](https://github.com/ukiuni/hidden.in) というsocket.ioを使ったビデオ会議をするプログラムを使用していました。
その際に、ユーザー名を表示させたいとの要望があり実装した備忘録です。

各バージョン

* Node v12.13.1
* express-session 1.17.1
* passport 0.4.1
* passport-local 1.0.0

[hidden.in](https://github.com/ukiuni/hidden.in)のインストール、使用方法については記事がありますので、参考にしてください。(また、後日まとめたいと思います）
インストール済みを想定して話を進めます。

少し話はそれますが、フォームにユーザー名を入力させてemitするといけるんちゃんと考え、実装したのですが、ブラウザをリロードすると消えてしまう為、ダメでした。

では、実装手順です

1. express-sessionとpassportとpassport-localをinstallする

```:tarminal
npm install i express-session passport passport-local
//インストール完了
```
2 requireして認証を実行する

```javascript:index.js
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　ルーティングの際にログイン済か認証する

```javascript:index.js
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を作成する

```html:views/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 -->
                &nbsp;
                <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でのセッション情報の取得の仕方は

```javascript:index.js
io.sockets.on('connection', function (socket) {
    console.log(socket.request.session.passport.user);
}
```

とすると認証されたユーザー情報が取得できるので、あとはこれをejsファイルで表示させてレイアウト整えるとユーザー名の表示の実装が出来る様になりました。
ユーザー名を表示させるプログラムについては、長くなったので別記事を用意したいと思います。

### 参考記事の皆様
[node.js socket.io上でsessionを使う](https://qiita.com/hika7719/items/d604ed4c35cdeb2228ff#%E3%82%BB%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92socketio%E4%B8%8A%E3%81%A7%E3%81%A4%E3%81%8B%E3%81%86nodejs)
[Node.js＋Express＋Passport を使ってみた
](https://qiita.com/tinymouse/items/fa910bf80a038c7f9ccb)