2018-09-16に更新

Nuxt.js+Expressで簡単にTwitter認証

Nuxt.jsとExpressでアプリケーションを作成する場合のTwitter認証でのログインを試してみました。Node.jsでのTwitter認証はPassportというライブラリを使用すると非常に簡単でした。細かく検証はしていませんがSSR(サーバーサイドレンダリング)の場合でも問題ないと思われます。

このあたりで作ったプロジェクトをベースにして試しています。

Nuxt.js+Expressでとにかく簡単にORM

  • Nuxt.js v1.4.2
  • Passport-twitter v1.0.4

インストール

何はともあれまずはインストールします。Passport本体とTwitter用の拡張です。

基本的なところは公式のマニュアル通りですので、よくわからなくなった場合やバージョンが違う場合はそちらを参考にしてください。

Documentation: Twitter

yarn add passport passport-twitter

初期設定

Passportの設定

まずはplugins/passport.jsとして初期化スクリプトを作成します。TWITTER_CONSUMER_KEY等は環境変数として指定しておいてください。(dotenv等を使うと便利です)

下記はSequelizeでユーザーデータとして保存する場合のサンプルも入れています。

var passport = require("passport"),
  TwitterStrategy = require("passport-twitter").Strategy;

module.exports = function(app) {
  const models = app.get("models");
  const User = models.User;

  passport.use(
    new TwitterStrategy(
      {
        consumerKey: process.env.TWITTER_CONSUMER_KEY,
        consumerSecret: process.env.TWITTER_CONSUMER_SECRET,
        callbackURL: `${process.env.APP_URL}/auth/twitter/callback`,
        includeEmail: true // メールアドレスが必要な場合
      },
      async function(token, tokenSecret, profile, done) {
        let user = await User.findOne({
          where: { twitter_id: profile.id }
        });

        if (!user) {
          user = User.build({
            unique_id: profile.username,
            name: profile.displayName,
            email: profile.emails[0].value,
            location: profile._json.location,
            bio: profile._json.description,
            url: profile._json.url,
            image: profile.photos[0].value,
            twitter_id: profile.id,
            twitter_token: token,
            twitter_secret: tokenSecret
          });
          await user.save();
        }

        done(null, user.get({ plain: true }));
      }
    )
  );

  passport.serializeUser(function(user, done) {
    done(null, user);
  });

  passport.deserializeUser(function(user, done) {
    done(null, user);
  });

  return passport;
};

認証用ルーティング

認証用のルーティングを作成します。今回はroutes/auth.jsとしてファイルを分けました。アクションにそのままPassportの処理を指定するようなので下記のようにしてルーティング設定全体を関数化して読み込む形にしました。

const { Router } = require("express");

module.exports = function(app, passport) {
  const router = Router();

  router.get("/twitter", passport.authenticate("twitter"));

  router.get(
    "/twitter/callback",
    passport.authenticate("twitter", {
      successRedirect: "/",
      failureRedirect: "/"
    })
  );

  app.use("/auth", router);
};

アプリケーションに組み込み

これらをserver/index.jsで読み込んでアプリケーションに組み込みます。

const passport = require("../plugins/passport")(app);

app.use(
  session({
    secret: "your secret"
  })
);
app.use(passport.initialize());
app.use(passport.session());

require("../routes/auth")(app, passport);

基本的な部分はこれで完了です。あとは実際に動かしていくための処理を入れていきます。

Nuxt.jsと連携させる

PassportでのログインはExpress側のセッションに保存しているだけのため、これをNuxt.js側にも渡します。アプリケーション全体に絡むことのため、Storeを使ってNuxt.js上のどこからでもアクセスできるようにします。Nuxt.jsの場合は下記のように適当にファイルを一つ追加するだけで簡単にStoreが利用できます。

store/index.js

export const state = () => ({
  authUser: null
});

export const mutations = {
  setUser(state, authUser) {
    state.authUser = authUser;
  }
};

export const actions = {
  nuxtServerInit({ commit }, { req }) {
    if (req.session.passport && req.session.passport.user) {
      commit("setUser", req.session.passport.user);
    }
  }
};

Storeの場合setUserでなくSET_USERが使われることが多い気がします。

あとはもう下記のようにゆるふわな感じで適当にログインしているか判断できます。

    <div v-if="$store.state.authUser">
      <img :src="$store.state.authUser.image">
    </div>
    <span v-if="!$store.state.authUser">
      <a href="/auth/twitter">ログイン</a>
    </span>

スクリプト側でもthis.$store.state.authUserみたいな感じで利用できます。

まとめ

荒い感じの書き方も一部あるかもしれませんが、とりあえず非常に簡単にTwitterログインを行ってNuxt.jsと連携させることができました。また動きのおかしいところなどあれば随時追記していきます。

他にもGoogleアカウントのログインなども公式のドキュメントに書かれています。


dala00

Crieitの開発者です。 主にLAMPで開発しているWebエンジニアです(在宅)。大体10年程。 業務依頼、同業種の方からのコンタクトなどお気軽にご連絡ください。 業務経験有:PHP, MySQL, Laravel5, CakePHP3, JavaScript, RoR 趣味:Elixir, Phoenix, Node, Nuxt, Express, Vue等色々

Crieitはαバージョンで開発中です。進捗は公式Twitterアカウントをフォローして確認してください。 興味がある方は是非記事の投稿もお願いします! どんな軽い内容でも嬉しいです。
なぜCrieitを作ろうと思ったか
関連記事

コメント