nuxt.js と serverMiddleware(express) で Twitterログインを実装した話


TL;DR

nuxt.js + serverMiddleware(express) でTwitterログインを実装した。

これはNuxt.jsとLaravelを使ってTwitterログイン機能を実装するにインスパイアされて書いてます。

上記の記事では、サーバサイドをLarabelで用意していますが、
そういえばnuxtのserverMiddlewareを使えばいいんではないかって思って実装を試した。

つまりこんな感じのことを実装しています。

twitter developer にて アプリ作成(省略)

アプリの説明を300文字書かなきゃいけなかったりとかこんな面倒だったっけか・・・

テンプレートからnuxtプロジェクトを作成

$ vue init nuxt-community/starter-template nuxt-twitter-auth
$ cd nuxt-twitter-auth
$ npm i --no-save
$ npm run dev

http://localhost:3000 で、まずは動作を確認します。

serverMiddleware を追加

  • 必要なライブラリを追加
$ npm install --save passport passport-twitter express-session body-parser cookie-parser
$ npm install --save axios
$ npm install --save morgan # optional
  • server/index.js を作成
  • CONSUMER_KEY と CONSUMER_SECRETを設定
  • 基本的にexpressなので、node経験者なら理解しやすいはず
server/index.js
const express = require('express');
const passport = require('passport');
const TwitterStrategy = require('passport-twitter').Strategy;

const app = express();
app.use(require('morgan')('combined')); // optional
app.use(require('cookie-parser')());
app.use(require('body-parser').urlencoded({ extended: true }));
app.use(
  require('express-session')({
    secret: 'some secret',
    resave: true,
    saveUninitialized: true,
    cookie: {
      secure: 'auto',
    },
  }),
);
app.use(passport.initialize());
app.use(passport.session());

// twitter
passport.use(
  new TwitterStrategy(
    {
      consumerKey: CONSUMER_KEY,
      consumerSecret: CONSUMER_SECRET,
      callbackURL: 'http://127.0.0.1:3000/callback',
    },
    function(token, tokenSecret, profile, done) {
      profile.access_token = token;
      profile.token_secret = tokenSecret;
      return done(null, profile);
    },
  ),
);

passport.serializeUser((user, done) => {
  done(null, user);
});
passport.deserializeUser((obj, done) => {
  done(null, obj);
});

app.get('/hello', (req, res) => res.send('world'));

// twitter
app.get('/auth/twitter', passport.authenticate('twitter'));
app.get('/auth/twitter/callback', passport.authenticate('twitter'), (req, res) => {
  res.json({ user: req.user });
});

app.get('/logout', (req, res) => {
  req.logout();
  res.redirect('/');
});

module.exports = {
  path: '/server',
  handler: app,
};

  • nuxt.config.jsにserverMiddlewareを追加
nuxt.config.js
+ serverMiddleware: ['~/server']
  • 起動
$ npm run dev
  • とりあえずserverMiddlewareの動作確認

http://localhost:3000/server/hello にアクセスして world が返ってくればOK

callback ページの作成 (twitterログイン後に返ってくるページ)

pages/callback.vue
<template>
  <section>
    <div>twitter user id: {{ user.id }}</div>
    <div>error: {{ error }}</div>
    <a href="http://127.0.0.1:3000/server/logout">logout</a>
  </section>
</template>

<script>
import axios from 'axios';

export default {
  data() {
    return {
      user: {},
      error: null,
    };
  },
  mounted() {
    // 1
    axios.get('http://127.0.0.1:3000/server/auth/twitter/callback', {
      params: this.$route.query,
    }).then(res => {
      // 3
      this.user = res.data.user;
    }).catch(err => {
      this.error = err;
    });
  },
};
</script>
  1. mountedでserverにtwitterから受け取ったクエリをそのまま投げてます。
  2. /auth/twitter/callback で serverはprofileを返してます。↓
  3. そして、vue側はtwitter userのIDを表示してます。
/server/index.js
// 2
app.get('/auth/twitter/callback', passport.authenticate('twitter'), (req, res) => {
  res.json({ user: req.user });
});
  • 最後に /pages/index.vue に /auth/twitter のリンクを追加すれば完成です
/pages/index.vue
<div class="links">
  <a
    href="http://127.0.0.1:3000/server/auth/twitter"
    class="button--grey">Twitter Login</a>
</div>

facebookとかlineもpassport使えば同じように実装できるはず

DEMO

Source Code

おしまい。