Rso's Jotter

日々の開発の知見のメモやその他雑記

Nuxt AuthModule + Auth0 + Rails での認証環境構築でのハマりポイントを残しておく

タイトルの通りなのですが、 以下の構成で認証する仕組みを試してみたら、思ったよりハマったのでその内容をメモしておきます。

  今回試した構成

  • フロント: Nuxt.js ライブラリは Auth Moduleを使用バックエンド:
  • バックエンド: Ruby on Rails
  • 認証および IdP: Auth0

  フロントエンドNuxtからでAuth0のauthorizeを呼び出し認証して、認証時にJWTを取得してそれをバックエンドに渡して認証する、ということをやろうとしました。 認証のサービスは Firebase Authや AWS Cognito など他にもありますが、Auth0が一番てっとり早くできそうなのかなと思い、こちらを採用したのですが、以下の点でハマりました。

 

JWTがAuth0から帰ってこない

フロントからの認証(authorize)まではすんなりいって、どうも返ってくるJWTらしき文字列が短い.. これはJWTでなくOpaque strings と呼ばれているもので、JWTでは無いようです。調べてみると、どうやらJWTを得るためには、audience を指定しないとかえってこないとのことでした。

auth0.com

OpenID Connectの仕様をあまり理解できていませんが、audience ってなんぞや、何のために設定しないと行けないのかももやっとしたまま、とりあえず設定方法を調べました。  

Auth-moduleで audienceの指定ができない

Auth Module の以下の issue を見ると、どうやら Auth Module 側で audience を指定することはできない様子。

github.com

じゃあどうするのかというと、 Auth0のconfig で default audienceを指定できるので、 それを指定すれば良いとのこと。

というわけで以下の設定画面で default audienceの設定を実施しました。

f:id:rso:20190504230715p:plain
Auth0での default audienceの設定

上記の設定を行なった後に認証を行なったら、 Opaque stringsでなく JWTを得ることができました。  

RubyのJWT認証 ライブラリ knockが現在のAuth0に対応していない

RubyでJWTを扱うライブラリでknock というgemがあったので、このgemで バックエンド側のJWTの検証を試しました。

github.com

auth0 + knockで認証を行なった例は検索でいくつか引っかかるも、どうやらAuth0から取得した JWTの 読み込みで失敗します。 上記のURLのissueでいくつかtopicが上がっていましたが、どうやら更新が長らく止まっているようで、いくつかクラスを書き換えれば動きそうなものの、ちょっと今後使っていくには厳しい印象を受けました。

なのでこのGemの採用は諦めて、公式のAuth0の Quick Startを参考に認証ロジックを自前で書いてやることで対応しました。

auth0.com

所感

上記の3点を解消したら無事に認証を実装することはできたのですが、思ったよりサクっとは行かず、試行錯誤が結構ありました。 Auth0側での仕様が変更されたりもあったので、過去の事例がそのまま参考にできなかったところが大きいと思います。 また、 実際に運用する上では OpenID Connectの仕組みをもう少し把握しておかなければいけないのかなと感じました。そちらに関しては別途理解をまとめた内容を残せればと思います。 

プログラミング初学者に伝えたい汎用的なデバッグ技法

プログラミング初学者はその知識量が少ないために、様々なところで躓きます。

訳のわからないエラーメッセージに遭遇し、ネットで調べてもさっぱり分からずに途方に暮れてしまいます。そして試行錯誤するも進んでいるの更に悪化してるのかも分からずに、ストレスがたまります。誰しもこのような経験を乗り越えて詳しくなって行くと思いますが、とりわけ初学者は原因の分からない問題に対処するノウハウが蓄積されていないのが、躓きの原因かと思います。

そこで、時間はかかりますが、原因が全く分からない問題に対処していける一つの手法を紹介します。

 ここで取り上げるケースは、以下の前提に基づきます。

  • トラブルの原因箇所は1つだけとするが原因は全く不明
  • 同じコードであればいつ実行しても同じ結果を返すとする(実行タイミングによる結果の変動はない)
  • 開発中のプロダクトを想定し、短期間で何度でも実行できる。
  • フロントエンド、バックエンド、プログラミング言語などは問わない

 

オススメのデバッグ方法

以下の3ステップです。

  1. 動く状態、またはHelloworldなど自分が理解できる動く小さなコードまで戻る
  2. そこから少しづつコード変更を加えていき、動いていた最終の状態と、動かなくなった最小の変更が何かを知る。
  3. 「動いていたこの最終の状態から、この変更を加えたら動かなくなりました。」と、先輩や詳しい人に聞いて助言を求める。  

動く状態まで戻る。これが全てなのですが、まずは自分の期待通りに動かせる最小、または最初の状態に戻ります。

リポジトリで管理していれば、最後に動作したコードにチェックアウトするがよいです。新しいライブラリやフレームワークを試しているのであれば、それが動作する最小のHelloWorldコードを実行するところまで戻ります。意外に気づくことがあるのですが、最小の動くコードに戻したと思ったらまだ対象のエラーに遭遇していて、エラーの箇所が調べていたところと全然異なっていたということもあります。

想定どおりに動かせる(コントロールできる)ところまで戻ることで精神的な余裕も生まれます。

この方法は限定した状況でのみ使える地味な方法ですが、確実に一歩一歩すすめますので、お試しください。

ブロックチェーンをゲームで使う意義

先日の マイクリハッカソン でゲームにブロックチェーンを組み込む意義みたいな話が出て、その内容が興味深かったのでメモしておきます。

 

なぜブロックチェーンでゲームを作るのか 

 

以下に内容はパブリックブロックチェーンを想定しています。

主な理由として以下の2点が考えられます。

 

永続性

プログラムが正常に動いてさえいれば、仮に運営がメンテナンスを放棄してしまったとしても、ゲーム自体は維持されます。人気のあるゲームが運営の金銭的な理由によってサービス停止されたり、一部のニッチ層だけが楽しんでいるゲームが維持できなくなり、停止するなどの事例はいままで起こっていますが、それが防げる可能性があり、ユーザのコミュニティで維持されることが期待できます。MMOのエミュ鯖が近いイメージです。

公正性

ブロックチェーン内の情報は誰もが閲覧できるので、その途中経過に不正がないことを証明でき、改ざんも防げます。またイーサリアムのようなコントラクトをブロックチェーンで管理することで、どのような処理が実行されるかも公開され、透過性を保つことができます。

またデメリットや、課題として、以下が挙げられます

複雑な処理ができない

現在のイーサリアムの仕組みでは、計算量がコストに結びつくため、複雑な処理をするほど費用がかかってしまうゲームになります。現時点ではこの計算コストが安くないため、ゲームの処理をブロックチェーン上で実行できたとしても、ごく単純な処理に限られてしまいます。その単純な処理だけでは、どうしても単調なゲームになりがちで、ゲームそのものの面白さを表現することが、ブロックチェーンを使わない従来のゲームに比べて難しいと考えられます。

 

改変の難しさ

ブロックチェーン状のプログラムや処理結果は改ざんが難しいという利点がある一方で、既存のプログラムをアップデートしたり、不具合を修正したりすることが従来よりも難しいと考えられます。この辺りは新たな方法が色々提案されていて、模索中の状態のようです。

ランダム性などのゲーム性の担保

プログラムが誰もが見れるというのは公正性を保てるという利点がある一方で、乱数の生成など、内容が見られてしまうことによって都合がよくない場合があります。乱数のアルゴリズムが分かれば、それを解析して有利な結果を得ることが可能になってしまいます。十分にランダムな乱数を得るためには計算量も大きくなってコストも上がってしまうというジレンマがあります。

所感まとめ

ゲームはブロックチェーンの適用例となる良い例かと思いますが、解消すべき課題はまだまだあるのかと思っています。ブロックチェーンを使用してプログラムを組むと、従来までのセオリーが通用しない部分があり、そのあたりがまだまだ発展途上なのかなと感じています。

 

 

マイクリハッカソンに参加しました

以下のハッカソンイベントに参加してきました。 www.mchhackathon.com

このゲームは多少知っていたのと、ブロックチェーンについて多少なりともキャッチアップできないかと思い、参加しました。

場所は HushHub さんのコワーキングスペースです。

以下やった内容をメモっておきます。

09:30 集合
10:00 開始。

ルール説明、スポンサーからのコメント、API解説など

11:00 チーム分け

最初からグループで来ている人も結構居ましたが、今回は知り合い2名+あらたに2名の計5名でグループを組むことに。

その後ハッカソン開始。 もともとイーサリアムネットワーク上で何ができるのかや、マイクリは何がイーサリアムチェーン上で管理されているのか、何がサイドチェーンなのか 確認、議論など。

11:00 - 15:00 何を作るか議論。

アセットをレンタルできるシステム案が有力で、実装可能かどうかを検討しました。

いろいろ話しているうちに、以下のような話になりました。

  • アセットを貸して返すということを実現するために、アセットを将来送るというコントラクトの実現が難しい
    • 借りている側がアセットを他に送ってしまい、持ち逃げされる可能性が残る
    • マイクリの仕組み上、アセットを使うにはイーサリアムネットワーク -> マイクリのサイドチェーンに送らないと遊べないので、イーサリアムネットワーク上にとどめておけない。
  • アセットを借りている側がアセットの価値同等もしくはそれ以上のイーサリアムを供託するという質屋モデルでなら実現可能。
    • 借りたアセットを返さないと供託金が没収される。
    • ただしそれだと少ない金額でレンタルしたいという要望は満たせないし、買ってからすぐ売るということとあまり変わりがない。

借りてちゃんと返したということを記録を評価として用いて、評価の良い人は供託金を少なくするシステムはどうだろうという 話も出て、それなら実現はできそうだがハッカソンネタとしてはあまり面白くないので、結局取り下げ。

他に出てきた代替案としては、今はアセット <=> イーサリアムの交換はできるが、アセット <=> アセットの交換をする仕組みがないので、 アセット同士を交換する仕組みをやってみようということに。さらに今までの掲示板モデルではなく、 チャットルーム形式で交渉できるような仕組みにしようということで、着手開始。

15:00 - 17:00 ようやく開発開始。

自分ともう1名でとりあえずバックエンドをペアプロ形式で準備。チャットルーム作成なのでSocket.io(websocket) を使うことに。 残り3名で コントラクト開発、自分のイーサアドレスからMetamask経由でアセット情報取得方法を調査。 フロントエンド・画面は... 空いた人がやることになりました。

17:00 - 21:00 開発継続..終わらず。

チャットルームの雰囲気ができたが、コントラクト側が難しそうなので、フロントエンドの準備も自分+もう1名で着手。 静的ファイルでよかったが、axiosやCSSフレームワークをさくっと入れたかったので、nuxt.jsを使用。

結局フロントとバックエンドのつなぎこみも不十分で、さらにコントラクトのつなぎ込みもできないまま、 タイムアップに。

21:00 開発した内容の発表

所感

結局発表時までに十分に動くものがデモできなかったのは残念で、 分かっていたことですが、ブロックチェーンに関する理解が不十分だったため、着手まで時間を要してしまい、 十分な開発時間を確保できませんでした。

また、今思うとデモで重要なポイントであるフロントエンド画面をおろそかにしてしまったのもあまりよくなかったなぁと思いました。 このあたりは残り時間の兼ね合いで注力すべきポイントをもっと絞るべきでしたね。 もっとフロントの実装を早くできるようになりたいところです。

即席で作成したグループでしたが終始良い雰囲気で開発できたのは良かったです。 とても疲れますが、良い勉強になったと思いました。

追記

マイクリハッカソン 表彰式で、CryptSpells賞をいただきました。 プロダクト自体はあまり作りきれなかったのですが、提案内容や背景に共感いただけたとのことでした。感謝です。

f:id:rso:20190427120023j:plain
award
CryptShellの限定アセットがもらえるとのことです。

Ruby 2.6.3 がリリースされました

Ruby 2.6.3がリリースされて、rbenvからもインストールできるようになりました。

forest.watch.impress.co.jp

新元号が対応したみたいなので、試してみました。

インストール(rbenvで)

 ruby-buildのアップデート
 $ cd /usr/local/rbenv/plugins/ruby-build/
 $ git pull
 $ rbenv install -l | fgrep 2.6.3                      ~
  2.6.3
 
 $ rbenv install 2.6.3
 $ rbenv global 2.6.3
 $ rbenv rehash
 $ ruby -v                                             ~
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-linux]

Version 2.6.3!!!

ためす

和暦にからむメソッドとして、Dateクラスの jisx0301 を叩いてみます。

 $ irb
 $ require "date"
 $ Date.new(2019, 4, 30).jisx0301
=> "H31.04.30"
 $ Date.new(2019, 5, 1).jisx0301
=> "R01.05.01"
 

令和元年!!!

以上です。久々の更新でこんなネタでいいんだろうか..