「JavaScriptでのWeb開発Node.js Express + MongoDB + ReactでWebアプリを開発しよう〜 その2 〜」の感想・備忘録

スポンサーリンク
「JavaScriptでのWeb開発Node.js Express + MongoDB + ReactでWebアプリを開発しよう〜 その1 〜」の感想・忘備録の続き

点数

60点

感想

書籍のタイトルにReactとあるが、結局Reactは出てこなかった。。
最後に「次回はReactを使用して…」と書いてあるが、続編は発売されていないらしい。。。
OAuthを使ったTwitter認証やmoment-timezoneなどは参考になったが、全体的にわかりづらかった。

OAuth

Twitterを使ったログイン

TwitterはOAuth1.0aに対応している。
以下の手順でAPI keyを取得することができる。
※事前にTwitter Developer Accountの登録が必要
https://www.itti.jp/web-direction/how-to-apply-for-twitter-api/

  1. https://developer.twitter.com/en/appsの「Create an app」をクリック。
  2. 「Enable Sign in with Twitter」をチェック。
  3. 「Website URL」にサイトのURL、「Callback URLs」に認証後のリダイレクト先URLを入力。
  4. 「Keys and tokens」タブにAPI keyとAPI secret keyが表示される。

passport-twitter

ExpressでTwitterを使用したOAuth認証を行うためのミドルウェア。
トークンはハードコードせずに、環境変数から取得するとよい。

  1. インストール
    npm install passport-twitter --save-dev
  2. 環境変数をセット
    export TWITTER_CONSUMER_KEY=xxxxx
    export TWITTER_CONSUMER_SECRET=xxxxx
    export TWITTER_CALLBACK_URL=xxxxxx
  3. app.js
const http = require('http');
const express = require('express');
const passport = require('passport');
const TwitterStrategy = require('passport-twitter').Strategy;
const session = require('express-session');

const app = express();

const twitterConfig = {
  consumerKey: process.env.TWITTER_CONSUMER_KEY,
  consumerSecret: process.env.TWITTER_CONSUMER_SECRET,
  callbackURL: process.env.TWITTER_CALLBACK_URL,
};

app.use(session({
  secret: 'b87ef9fb4a152dbfe4cf4ea630444474',
  resave : false,
  saveUninitialized : false,
}));
app.use(passport.initialize());
app.use(passport.session());

passport.use(new 
TwitterStrategy(twitterConfig,
  // 認証後のアクション
  (token, tokenSecret, profile, done) => {
    // callbackURLへリダイレクトされる
    return done(null, profile);
  }
));
app.get('/', (req, res, next) => {
  res.send(`id:${req.session.user.id}`);
});
app.get('/oauth/twitter', passport.authenticate('twitter'));
app.get('/oauth/twitter/callback', passport.authenticate('twitter'),
  (req, res, next) => {
    req.session.user = req.session.passport.user;
    return res.redirect("/")
  }
);
passport.serializeUser((user, done) => {
  done(null, user);
});
passport.deserializeUser((user, done) => {
  done(null, user);
});

const server = http.createServer(app);
server.listen('3000');

connect-mongo

セッション情報をメモリではなくMongoDBに保存するために必要なライブラリ。
デフォルトではsessionsという名前のコレクションに格納される。

  1. インストール
    npm i connect-mongo --save-dev
  2. app.js
const MongoStore = require('connect-mongo')(session);
// 〜省略〜
app.use(session({
  secret: 'b87ef9fb4a152dbfe4cf4ea630444474',
  resave : false,
  saveUninitialized : false,
  store: new MongoStore({
    mongooseConnection: mongoose.connection,
    db: 'chatapp',
    ttl: 14 * 24 * 60 * 60,
  }),
  // cookie: { secure: true },
}));

セキュリティ

helmet

セキュリティー関連の9個のHTTP ヘッダーを適切な値にセットしてくれるミドルウェア。
https://www.npmjs.com/package/helmet
使い方は、requireでモジュールを読み込んでuseでミドルウェアとして利用するだけ。

  1. npm install helmet --save-dev
  2. app.js
const helmet = require('helmet');
// 〜省略〜
app.use(helmet());

csurf

CSRF対策のためのミドルウェア。

  1. インストール
    npm install --save-dev csurf
  2. app.js
const csrf = require('csurf');
const csrfProtection = csrf();
// フォームと送信先のルーティングでミドルウェアを使う
app.get('/form', csrfProtection, (req, res, next) => {
  res.render('index', {csrf: req.csrfToken()});
});
app.post('/', csrfProtection, (req, res, next) => {
  res.render('index', {message: req.body.message});
});
  1. テンプレート
input(type="hidden" name="_csrf" value=csrf)

エラーはExpressデフォルトのエラーハンドラで処理する。
err.codeEBADCSRFTOKENがセットされる。

app.use(function(err, req, res, next) {
  log.error(err);
  if (err.code === 'EBADCSRFTOKEN'){
    res.status(403)
  }else{
    res.status(err.status || 500);
  }
  return res.render('error', {
    message: err.message,
    status: err.status || 500
  });
});

cors

最近はCORS(Cross-Origin Resource Sharing)を解除してAPIを公開する需要が増えてきた。
CORSを許可するにはHTTPヘッダに許可するための記述が必要となる。
Expressではcorsというミドルウェアを使う。

  1. インストール
    npm install cors --save-dev
  2. app.js
const cors = require('cors');
// 全てのルーティングでCORSを許可する場合
app.use(cors());
// 特定のルーティングのみCORSを許可する場合
app.get('get-json', cors(), (req, res, next) => {
  res.json({hoge: 'hogehoge'});
});

オプションを指定すると、ホストやHTTPメソッド単位での許可が可能となる。

https

Expressではhttpsミドルウェアを使うことで、プロトコルをhttpsにすることができる。
httpsミドルウェアはExpressに含まれているので個別のインストールは不要。
秘密鍵とサーバ証明書はあらかじめ用意しておく。

const fs = require('fs');
const https = require('https');
const options = {
  key:  fs.readFileSync('../lets_encript.key'),
  cert: fs.readFileSync('../lets_encript_fullchain.crt')
};
// 〜省略〜
const server = https.createServer(options, app);                      
server.listen(3000);

moment-timezone

JavaScriptのDateオブジェクトは実行環境によっては世界標準時となってしまう。そして出力が見づらい。
moment-timezoneがその2つを解決してくれる。
※moment-timezoneはmoment.jsの上位互換版

  1. インストール
    npm install moment-timezone --save-dev
  2. app.js
const moment = require('moment-timezone');
moment.tz.setDefault("Asia/Tokyo");
console.log(moment().format('YYYY-MM-DD HH:mm:ss'));

moment.jsはサーバのロケールを設定する必要がある。
moment-timezoneの場合は必要ない。
https://www.kwbtblog.com/entry/2019/10/05/152745

Expressでのログアウト処理

passportを使うとreq.isAuthenticated()メソッドが追加される。
req.isAuthenticated()を使ってログイン状態を判定するミドルウェア(関数)をルーティングに追加する。

const checkAuth = (req, res, next) => {
  if (req.isAuthenticated()) {
    next();
  }
  else {
    res.redirect('/oauth/twitter');
  }
};
app.get('/', checkAuth, csrfProtection, (req, res, next) => {
  // 処理
});

また、passportを使うとreq.logout()メソッドが追加される。

app.get('/logout', checkAuth, (req, res, next) => {
  req.logout();
  delete req.session.user;
  res.redirect('/');
});

コメント