新しいシステムの開発に必要不可欠だと僕が思っているもののひとつに
SPAというのがあります。シングルページアプリケーションです。
twitterの新しいGUIがわかりやすい例ですかね。画面のすべてをjavascriptで構成し、1つのページで完結させるっていうモダンなフロントエンド技術のことです。
もっと具体的にいうと、画面遷移してないけどURLはきちんと変わってるやつ、あれはSPAによるものです。
メリットとしては、ページ(全体)の読み込みなどが発生しないので画面遷移がスムーズであること、そして
スマホアプリ対応も非常にラク(らしい)というのが大きなメリットです。
もちろんデメリットとしては読み込むページのサイズが大きくなるので最初の表示が遅くなること、SEO的にはちょっと微妙なラインだったりするらしいこと、あと当たり前ですけど開発の工数が増えるということですね。
ただ、それを補ってあまりあるメリットのある技術ですので導入しない手はないわけです。
僕が開発する予定のORGSM(仮)でも、slackのようなチャットモジュールを導入する予定でして(使ったことないけど)、そのあたりでは大きな効力を発揮することが予想されます。
それに、javascriptベースにすることでPush.jsを用いてブラウザにプッシュ通知を搭載することも容易になるはず、という大きなメリットもあります。
必須かっていわれたら必須ではない技術ですが、先々のことも考えるとやっぱり導入したい技術だし、僕自身も技術的に一皮むけてさらに自由にアプリケーションを作れるようにならなくては、ということで久しぶりに新規技術のお勉強をしたいなと思ったわけです。
で、その具体的な実装がこの前ちょこちょこっと書いたVue.jsだったりReact.jsの話だったりするんですが・・・・・・
試しに動かしてみてすごい感動したんですけど、未だにクリアできていない課題があります。
認証がわからない。
いろいろ調べてみて
API認証っていうのが使えるらしく、Laravelにも
Passportっていうライブラリがあるみたいで、それを使えばOAuth認証が実装できるらしい・・・・・・んですが、マニュアルを呼んでも正直あまりよく理解できませんでした・・・・・・。
で、その原因は
僕がAPI認証に関して根本的な理解をしようとする気がなかったことに由来します。
さすがにゼロ知識ベースではムリだなと判断したので、API認証の仕組みについて調べて、この日記に書き残したいと思います。
もちろんAPI認証っていってもいろんな種類があるのですが
このページを読み解いてみるのが良さそうな気がします。
まず、必要な情報はこんな感じらしい。こいつをaxiosとかいうライブラリを使ってAjax通信させてやりとりするとトークンが手に入るらしい。
このシークレットキーっていうのが・・・・・・
たぶんこいつのことです。
実際に生み出されたものがこんなふうにDBに格納されているのを観測しました。
ユーザーごとにリダイレクト先を変えられるのがPassportの実装なんですかね、へえー。
で、ユーザーテーブルの名前とパスワードを送信すればいいのね。
このパスワードは平文じゃなく、userテーブルの、っていうことはこの暗号化したパスワードを送ればよさそうかなって思ったんですがそうでもないみたい(後述)。
これをpostするとアクセストークンが取得できるらしい。
で、これを読み解きましょう。
on:click=Loginとか書いてますので、これをクリックするとmethods内のLogin()メソッドが呼び出されるのが想像できますね。わかりやすい。
ここで変数としてパスワード方式であることを示すgrant_type、client_idは2を指定するらしい。ここがちょっと怪しいですね。パスワードモードであることを示すidではなさそう。
DBを見たところ、このpassword_clientがtrueになってるので、このユーザーを指定するための"2"なんだと予想します。
パーソナルアクセストークンってなんや???って思ったんですけど、
ここを見る限りサポートを切って良さそうですね。つねに0を指定したいところ。
さっき貼ったリンク先ではこうなってます。こちらはハードコーディングで指定しているものですね。
ユーザーネームとパスワードは平文で良さそう。つまりここを盗聴されないようにってことですね。まぁ変なアドオンがなかったら盗聴はされないはずですけど・・・・・・。
再掲ですが、こちらの実装の場合はthis.usernameから直接プロパティの値を持ってこれるみたいですね。v-modelってのはなんか関係あるんですかね?まぁここはそんなハマらなさそうなにおいがするので後でnuxt勉強する時に考えれば良さそうです。
で、このpostDateオブジェクトをコンソールに吐き出してます。あれ、nuxtの記法ってセミコロン要らないんですか??へえ・・・・・・。
それで、axios.postを実行します。URLはoauth/token固定みたい。Passport::routes()で定義しているんだと思います。
このページにも載ってましたが、こんな感じのレスポンスが返ってくるそうです。参考するサイトがコロコロ変わりますね(笑)
このアクセストークンをheaderに入れることで、middleware('auth:api')のガードを通過できるようになるみたいです。
ここ、ぱっと見ちょっとよくわからないですね・・・・・・。ラムダ式ですねきっと。
responseを引数として、headersという変数に、返ってきたデータのアクセストークンにぶちこんでます。
で、axiosのheaders.commonのAuthorizationとかいうのにぶちこんでるんですが、たぶんここが常時参照されるグローバル変数っぽい気がします。
ところでheaders.Authorizationってなんでしょう??アクセストークンって実体はオブジェクトなのかな???Authorizationなんていうフィールドなんかあったか???
あ、よく見たらgetHeadersって関数を呼び出してたみたいですね。ここでthisとか言えてるってことは、どこでthisって言ってもこのビューファイルを指すことになりそうですね。
受け取ったトークンに
"Bearer "っていう文字列を付与してAuthrizationという連想配列に入れてるみたいですね。拡張性のためでしょうな。とりあえずこれで動きが見えました。
このコードだけだとこの先どうしたらいいのか想像ができないので、参照するページを変えましょう。
ほーーーんなるほどなぁ~~。とりあえず認証の方法はわかったんですが、いまいち使い方がよくわかりませんね。
うーん。APIの使い方としては、とりあえずヘッダーにトークンをくっつけで送信すれば、認証情報が返ってくるので、それをもとに処理をする・・・・・・って流れになるんでしょうか。
認証情報がOKだったらコントローラーに行って、適切な処理を施して必要なデータだけ返す、っていう使い方はできないんですかね・・・・・・?
あーでもauth:apiミドルウェアを指定してるだけだし、コントローラーに処理がうつるのでこれは標準で搭載されているテスト用の関数、ってだけでもっと別の動作ができるのかな???
それができれば勝ったも同然っぽい感じがする。
調べてもよくわからなさそうなので、実装したほうが早そう。やるか。
APIの実装に関してまとめると、IDとパスワードをサーバーに送信し、合致していればシークレットトークンを返却、そのトークンをヘッダーに埋め込むことでログイン状態、ということにする感じかな?
認証情報を常に保持しているっていうのはセキュリティ的にもヘンですからね。
技術背景について調べてみると
こういうエントリを見つけたんですが、おおよそ僕の理解と合ってたっぽいですね。
ただ、この認証方式は
自社のスマホアプリなど、APIを利用するクライアントの提供元が自社であることが確実に証明できる場合と書かれています。まぁログイン情報を入力させるわけですからね。
こういう問題が起きうるわけですね。つまり、僕がこういう認証方式を外部に公開した時点で、emailとpasswordの組み合わせを知られてしまうといとも簡単にこっちのサーバーの情報が抜き取られてしまう、そういう理解でオッケーですかね???
僕のプロダクトで触れることはあんまりなさそう、とは思うのですがAPIを外部に公開する際はこのような実装方式にしましょうね~~っていう。
仕組みは簡単ですね。トークンだけを渡して、それをもとにアクセスしてもらいましょ、と。
アクセストークン・リフレッシュトークンの使い方や動きなども以降の文章を読んで理解しました。とりあえずAPI認証のメカニズムはそんな感じらしいですね。はいはい。
ということで、勉強にかんしてはこれで区切りをつけ、いつになるかわかりませんが、次回実装編ということで成果発表会します(笑)