FJCT_ニフクラ mobile backend(mBaaS)お役立ちブログ

スマホアプリ開発にニフクラ mobile backend(mBaaS)。アプリ開発に役立つ情報をおとどけ!

サーバサイドでmBaaSの認証を使うには

f:id:mbaasdevrel:20180416173340p:plain

mBaaSはスマートフォンアプリ向けのサービスですが、バックエンドとしてだけ見ると、何もアプリだけに限りません。一般的にサーバサイドで必要になる認証、データベース、ファイルストレージなどmBaaSを使うことで管理が不要になります。

そこで今回はJavaScript SDKを使ってWebサービスを構築する方法について紹介します。まず最初に問題になりそうな認証の行い方です。

なぜ認証が問題になるのか

通常、JavaScript SDKを使っているのは個人の端末になります。そのため、認証データ(セッションIDなど)は個人の端末にしか保存されません。しかし、サーバサイドで使う場合にはサーバサイドがユーザに変わって認証を行うようなものです。その結果、セッションIDがサーバ側に返ってきます。

このセッションIDはユーザの認証情報になります。そのため、セッションIDが漏洩したり、書き換えられることで他人のデータにアクセスできる可能性があります。そうならないために、多くは別途セッションを保存しておくデータベースを用意しますが、mBaaSを使っているのにデータベースを用意するのは面倒でしょう。

そうした問題を解決できるのがJSON Web Tokenになります。

JSON Web Tokenとは?

JSON Web TokenはURLセーフなトークンです。URLセーフというのはURLに使えない文字を含まない、という意味です。基本はJSONですが、Base64でエンコードすることでURLセーフにしています。そして、情報を改ざんできないという特徴があります。情報を基に署名を行っており、情報を改ざんすると署名が変わるので検知できるという仕組みです。

JSON Web Tokenは全部で3つのパートからなります。それぞれのパートをドット(.)でつないだのがJSON Web Tokenです。

  • ヘッダー
  • ペイロード
  • 署名

の3つで、ペイロードに情報を入れます。サーバ側ではWebブラウザから送られてきたJSON Web Tokenが改ざんされていないことが確認できれば、そこに入れられた情報(セッションIDなど)を安心して利用できます。

Node.js向けには jsonwebtoken というライブラリが使えます。

サービスを作る

では実際に使ってみましょう。今回はNode.js + Expressで作っていきます。Expressのベースを生成するExpress generatorが便利です。

$ npm install -g express-generator

まずベースを生成します。

$ express ncmb_server

そしてライブラリをインストールします。

$ cd ncmb_server/
$ npm install

ライブラリをインストール

まずはJavaScript SDKをインストールします。

$ npm install ncmb --save

後は前述のJSON Web Tokenをインストールします。

$ npm install jsonwebtoken --save

ログイン処理を作る

今回はあらかじめユーザを作成してあることとします。 routes/sessions.js にてログイン処理を作ります。ログイン画面は GET /sessions で表示します。

var express = require('express');
var router = express.Router();
var jwt = require('jsonwebtoken');

/* GET users listing. */
router.get('/', function(req, res, next) {
  res.render('sessions/index');
});

テンプレート(Jade)は次のようになります。

extends ../layout

block content
  h1 ログイン
  form(action="/sessions",method="post")
    p ユーザID 
      input(type="text",name="userId",placeholder="ユーザID")
    p パスワード 
      input(type="password",name="password",placeholder="")
    p
      button(type="submit") ログイン```

f:id:mbaasdevrel:20180416173209p:plain

ログインは POST /sessions にて行います。 app = module.parent.exports でExpressのアプリケーションインスタンスを受け取れるのがコツです。今回はJSON Web Tokenを24時間の有効期限でセットしています。jwt.sign で署名を作成します。その署名をCookieにセットします。

router.post('/', (req, res, next) => {
  const app = module.parent.exports;
  const ncmb = app.get('ncmb');
  const secret = app.get('secret');
  ncmb.User
    .login(req.body.userId, req.body.password)
    .then(user => {
      console.log(user);
      const userHash = {
        userName: user.userName,
        objectId: user.objectId,
        mailAddress: user.mailAddress,
        sessionToken: user.sessionToken
      }
      var token= jwt.sign(userHash, secret, {
        expiresIn: '24h'
      });
      res.cookie('token', token);
      res.redirect('/');
    })
});

トークンですが、以下のような文字列になります。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyTmFtZSI6InRlc3QiLCJvYmplY3RJZCI6IkVhZ05uaHQzTXY1eDlLVUsiLCJtYWlsQWRkcmVzcyI6bnVsbCwic2Vzc2lvblRva2VuIjoiVHpTajA2c3l2RWVnUEk1bU1yajgwdGNEdyIsImlhdCI6MTUyMzYwMjA0OSwiZXhwIjoxNTIzNjg4NDQ5fQ.Tt5Y4lxiE13RqQIsukGUXowXlzkT32JDBLT14sFef7w

このトークンをドットで分割した時、二つ目の文字列がペイロードになります。

{
  "userName":"test",
  "objectId":"EagNnht3Mv5x9KUK",
  "mailAddress":null,
  "sessionToken":"TzSj06syvEegPI5mMrj80tcDw",
  "iat":1523602049,
  "exp":1523688449
}

この文字列を改変したりするとJSON Web Tokenとして使えなくなります。

データを登録する

ではこのトークンを使ってデータ登録処理を行います。この時には Cookieから送られる文字列が使えます。 jwt.verify を使ってJSON Web Tokenの検証とデコードができます。エラーにならなければ改ざんされていないということなので、そのまま使えます。

ncmb.sessionToken にセッショントークンを当てはめれば認証状態としてサーバにアクセスできます。

router.post('/', (req, res, next) => {
  const token = req.cookies.token;
  const app = module.parent.exports;
  const ncmb = app.get('ncmb');
  try {
    const json = jwt.verify(token, app.get('secret'));
    ncmb.currentUser  = new ncmb.User(json)
    ncmb.sessionToken = json.sessionToken;
    const Todo = ncmb.DataStore('Todo');
    const acl = new ncmb.Acl;
    acl
      .setUserReadAccess(ncmb.currentUser, true)
      .setUserWriteAccess(ncmb.currentUser, true);
    const todo = new Todo;
    todo
      .set('txt', req.body.txt)
      .set('acl', acl)
      .save()
      .then(todo => {
        res.redirect('/todos');
      })
  } catch (e) {
    
  }
});

このようにしてACLにも対応したデータを保存したり、表示できます。

f:id:mbaasdevrel:20180416173228p:plain

まとめ

今回のコードはNCMBMania/server_demo: mBaaSをサーバサイドで使うデモです。にアップロードしてあります。認証データの取り回しができれば、後はWebブラウザで使うJavaScript SDKとほとんど使い方は変わらないでしょう。

サーバサイドでmBaaSを使うことで、アプリとのデータ共有であったり、サーバサイドでありがちな機能をあらかじめ実装しておいた状態で使える、さらにデータベースを用意しないでいいといったメリットがあります。ぜひお使いください!

中津川 篤司

中津川 篤司

NCMBエヴァンジェリスト。プログラマ、エンジニアとしていくつかの企業で働き、28歳のときに独立。 2004年、まだ情報が少なかったオープンソースソフトの技術ブログ「MOONGIFT」を開設し、毎日情報を発信している。2013年に法人化、ビジネスとエンジニアを結ぶDXエージェンシー「DevRel」活動をスタート。