Mi in progress

研究者の道ではなく、エンジニアになることを決意した人のブログ。

Twitter課題修正プロジェクト - 認証・認可・OAuth2.0の復習をしよう

お久しぶりです。

つい先日、会社の研修が全て終わって業務が始まりました。

前回の記事で、JavaとRustの違いについて学ぶと豪語したものの...研修課題が難しすぎて、プラスαで学ぶ余裕がありませんでした。宣言を守れていなくてごめんなさい。

Rustに関しては技術書典3で記事を寄稿すると決めたので、そこに向けて勉強を再開するつもりです。

追い風と勝手に感じたのですが、ついにオライリーからRustの本がでるみたいです!

日本語訳出ないかな... 

Programming Rust: Fast, Safe Systems Development

Programming Rust: Fast, Safe Systems Development

 

 ---

余談はこれくらいにして、本記事の本題に移ります。

研修最後の課題がTwitter実装だったのですが、動けばいいだけのゴリゴリコーディングをしてしまいました。お師匠に教えていただいた内容をキャッチアップしきれていない状態なので、空き時間にリファクタリングを進めていきたいと思います。

このプロジェクトのゴールは個人用のAWSTwitter課題を公開し、社外の友達に見てもらうことです!

まずは認証部分のリファクタリングを行います。

 

使っているツール(前提条件)
  • Spring boot
  • Spring security
  • Java 8
  • Docker (mysql 5.6)
  • Flyway

 

どんな風に現状のコードが酷いのか?(自己分析)
  • そもそも認証、認可、OAuth2.0のことをよく理解していない
  • AbstractPreAuthenticatedProcessingFilterのことをよく理解しないまま実装に使った
  • 他のControllerが@RestControllerなのに、なぜか認証に関するControllerだけ@Controllerになっている
  • ユーザー名とパスワードの照合ができたときにアクセストークンを発行するのだが、jsonでクライアント側に返すのではなく、ヘッダーに入れて返している(お作法的にとっても気持ち悪いとのこと...)

 

どう直していくか
  1. 認証認可について理解を深める
  2. OAuth2.0について理解を深める
  3. AbstractPreAuthenticatedProcessingFilter使用例を見て、お作法を学ぶ
  4. 設計図を書く
  5. 見積もりをする
  6. 実装

 

認証認可について理解を深める

早速、認証認可についての理解を深めていきたいと思います。

「認証認可って何が違うんだ...一緒じゃないの?」

そんな迷える子羊だった私を救ってくれた記事がこちらでした。

dev.classmethod.jp

認証 ... 通信の相手が誰(何)であるかを確認すること

認可 ... とある特定の条件に対して、リソースアクセスの権限を与えること

普段よく使っているTwitterFacebookは、認証(ユーザー名とパスワード照合で本人であることを認める)と認可(本人として、投稿やいいね等ができるようになる)が同時に行われているものだったので、疑問が浮かんでしまったんですね。

 

OAuth2.0についての理解を深める

自作Twitterのログイン・ログアウト実装の際、

「今回は認可サーバーとリソースサーバーを分けないけど、OAuth2.0のResource Owner Password Credentials Flowの考え方で、APIへのアクセストークンを発行してみよう」

というお達しをもらったのですが、「ログインといえばCookieやセッション」しか知らなかったので、初めて教えて頂いた時に頭がパンクしたのを覚えています。

改めてOAuth2.0について理解を深めていきます!

まずは、OAuthが必要になった背景についてですが、wikipediaに端的にまとめられていました。

マッシュアップによるWebサービスの連携が増え、デジタルアイデンティティの共有が問題となってきた。OpenIDのような連合アイデンティティが解決策として登場したが、これはIDの持ち主による認証手段であって、それによってどのリソースにアクセスできるかという認可については扱っていない。あるWebサービスAにユーザーの個人情報があるとき、そのWebサービスAと別のWebサービスBが連携し、WebサービスAにある個人情報をWebサービスBが自由にアクセスできる状況は好ましくない。そのため、WebサービスAPIへのアクセスを認可する手段が必要とされていた。

続いて、Resource Owner Password Credentials Flowについてです。これについては、素晴らしいQiitaの記事で学ばさせて頂きました。

qiita.com

ここで疑問に思ったのが、「Resource Owner Password Credentials Flowだと、アプリ側がusernameやpasswordを持つことになってしまうけど、いいのかな?」ということです。このような疑問について、RFC 6749にこのようなことが書いてありました。

The resource owner password credentials grant type is suitable in cases where the resource owner has a trust relationship with the client, such as the device operating system or a highly privileged application.

It is also used to migrate existing clients using direct authentication schemes such as HTTP Basic or Digest authentication to OAuth by converting the stored credentials to an access token.

つまりこのフローは、クライアントが極めて信頼できる場合もしくはOAuthへ移行する場合に有効だということです。

今回のTwitter課題においては、「移行」というより「拡張性」という言葉が適切かもしれません。

「今はusernameもpasswordも自分たちのサーバーで管理しているけど、いつかは他のサービスに認証部分を任せるかもしれない。」

「他のサービスを使っているユーザー情報で認証するようになるかもしれない。」

そういった場合にこのフローをあらかじめ採用しておけば、一から新たに認証・認可に関する部分を作る必要がありません。

ソフトウェアの拡張性を高めるために、お師匠はResource Owner Password Credentials Flowを採択したのだと理解できました。...合ってるかな?笑

あとで確認します。

 

今日はここまで。

次回はAbstractPreAuthenticatedProcessingFilterの使用例を見て、お作法を学んでいきます。