ワイ認証が全然分かっていない
認証
部分は自分が実装する前にパイセンエンジニアが既におおむね、下地を作った状態で、「これ使ってね〜」状態になっている事が多く、初期の開発に参加出来なかったりする。過去に趣味開発でOauth
なりを使用したことはあるが、コピペで作ったので正直、よく覚えていないし理解もしていなかった。
最近はバックエンドでの開発が多いので、自分の苦手分野でもある認証
について改めて理解を深めたいと思った。
ざっくりと調べてみた
認証と言っても幅広く、様々なものあった。簡単に今回、目にしたものをリスト形式で書き出した。
(調査時のメモはgitのREADME.mdに記載しました)
- SSO(SingleSignOn) -> eg: 免許書1枚で様々な契約が可能
- Basic認証
- IDとPASSをheader paramaterに含めて送信して認証
普段よく聞く単語と出会うことが出来た。Web開発をメインでやっているので、自分と最も関わりが深いのはOauth
だと思うし、最も気になる所。
Oauth
の流れについては以下の記事が驚く程、分かりやすかった。
確かに一番分かりやすい。
動くものを作って学ぶ
やはり、動くものを作って理解を深めたいのでTwitter
なりのAPIを申請しようかと思ったが、申請期間を待ったり、合わせてデータベースを用意したりするのが面倒だったので、今自分が持っているレシピの中でサクッと作れるであろう、プロセス間通信を利用してOauth
の流れを再現してみようと思う。
概要図
処理の流れについて図にまとめた。以下のようにプロセス間通信を行い、一連の認可(Oauth
故)の処理を行えば、再現出来ていると言えるのではないだろうか。
実装
上記の図に登場した3つのプロセスをそれぞれモジュールで表現する。
- メインプロセス ->
OauthDemo
- 認証サーバー(認証を実行するプロセス) ->
OauthDemo.Server.Authorization
- リソースサーバー(リソースを返却するプロセス) ->
OauthDemo.Server.Resource
順にそれぞれを簡単に解説しておく。
メインプロセス
他2つのプロセスを立ち上げて、一連の処理の流れを実行するためのプロセスとなる。command line
から受け取った引数によって、実行する処理を流れを変更する。
PASS
-> 認証に成功してリソースの取得が可能UNAUTHORIZED
-> 認証に失敗してアクセストークンの発行がされないUNVALID_TOKEN
-> 認証にし成功してアクセストークンが発行されるが、有効ではないトークンが送られるためリソースの取得に失敗
認証を実行するプロセス
このプロセスは2種類のメッセージを受け取り、認証処理を実行する。ユーザー情報の保持には、サーバーにkey valueのobject(Elixir
ではmap
)を保持させて、管理している。なお、パスワードのハッシュ化や暗号化は簡単のために今回は行っていない。合わせて、ユーザー情報はプロセスを立ち上げる際に、Faker
という外部ライブラリを使用して、適当な名前(id
)とパスワード(password
)を作成している。
eg: ユーザー情報
[ %{"id" => "yu-gi", "password" => "atemu"}, %{"id" => "kaiba", "password" => "mokuba"}, %{"id" => "zyo-no-chi", "password" => "sizuka"}, ]
AUTH
eg: 認証に成功した後のuser情報
[ %{"id" => "yu-gi", "password" => "atemu", "access_token": "xxxxxxxxx"}, %{"id" => "kaiba", "password" => "mokuba"}, %{"id" => "zyo-no-chi", "password" => "sizuka"}, ]
リソースを返却するプロセス
ここでは1種のメッセージ(as requset)を受け取り、処理を実行する。
REQUEST
- 送られてきたアクセストークンを認証を実行するプロセスにメッセージ経由で送信
- 認証結果を受け取り、
true
(通過)した場合はリソース(今回は簡単のため、ただの文字列)をメッセージを通して返す。false
の場合は401error
をraiseする
実行結果
処理の流れが確認できるようにloggerを仕込んであるので、順に結果を確認してみよう。
先にiex -S mix
を使って、iex
を立ち上げておく。
AUTH
iex(1)> OauthDemo.main("PASS")
# id => Ollie, password => 4HDiMF8jを受け取り、認証を実行 10:47:16.365 [info] Received request 'Oauth': id => Ollie, password => 4HDiMF8j # 存在するユーザーだったため、アクセストークンが発行される 10:47:16.377 [info] Created access token: access_token => husjlbdpho # リソースサーバーにリクエスト。合わせて認証を実行するプロセスでアクセストークンの確認を行う 10:47:16.377 [info] Received request 'Confirm': access_token => husjlbdpho # 問題ないアクセストークンであったため、リソースを返す 10:47:16.378 [info] Received request: passed authorization # 返ってきたリソースを出力 [Success] Response: Nasubi :ok
UNAUTHORIZED
iex(2)> OauthDemo.main("UNAUTHORIZED")
# id => okabe, password => 1234を受け取り、認証を実行 10:52:29.226 [info] Received request 'Oauth': id => okabe, password => 1234 # 存在しないユーザーだったため、アクセストークンが発行されず401 errorをraise 10:52:29.227 [info] Unauthorized. Not registed user => okabe # 認証失敗の結果が返ってきたことを確認し出力 [Success] Response: Unauthorized :ok
UNVALID_TOKEN
iex(3)> OauthDemo.main("UNVALID_TOKEN")
# id => Derrick, password => ebOyk+eoを受け取り、認証を実行 10:54:08.658 [info] Received request 'Oauth': id => Derrick, password => ebOyk+eo # 存在するユーザーだったため、アクセストークンが発行される 10:54:08.658 [info] Created access token: access_token => bsnmpgfrhb # リソースサーバーにリクエスト。合わせて認証を実行するプロセスでアクセストークンの確認を行う 10:54:08.658 [info] Received request 'Confirm': access_token => xxxxxxxx # 不正なアクセストークンだったため、401errorをraise 10:54:08.659 [info] Received request: unauthorization # 不正なアクセストークンによる失敗の結果が返ってきたことを確認し出力 [Success] Response: Unvalid token :ok
最後に
一連のOauth
の流れを作成して覚えることが出来た。今回は簡単のため、多くの機能やアーキテクチャを省略している。パスワードが筒抜けなのはありえないし、ユーザーの新たな追加やユーザー情報の確認など、追加しようと思えばいくらで機能は追加が可能だが、今回の本流となるところではないので、触れなかった。少しは認証に強くなれたと思いたい。