つかびーの技術日記

情報系修士卒のWeb系技術日記です。現在のフォーカス分野はアドテクです。

REST(JAX-RS, Jersey)を使ったシステムで認証を導入するには

      2013/11/17

今回はRESTによるシステム作るとき、認証をどのように実現するかについて書きます。以下のやり方だとセッションを張るので、それRESTじゃないじゃん、と言われるかも知れませんが・・・。(RESTで認証するならクライアント側からトークンを送ってリクエストごとに認証するかどうか判断するのが妥当かもしれません。)とにかく最善の実装ではない可能性はありますが、書いてみます。

Jerseyなんかを使うと簡単にWebアプリケーションまたはWebサービスを作ることができます。

EclipseでMavenプロジェクトを作成する時に、「jersey-quickstart-webapp」を選択するだけでOKです。

jersey-quickstart-webapp

今回はこれをもとに、認証ありのリソースと認証なしのリソースを返却するWebサービスを作成します。

Jerseyを使ったRESTシステム

まずはそのリソースを返却するコードを用意します。

web.xmlは以下のように書きます。

今回はFORM認証なので、login.htmlとerror.htmlも用意します。BASIC認証やDIGEST認証でも良いと思いますが、ウィンドウが簡素なので、FORM認証を選択します。自由度高いですし。

login.html

error.html

最後にtomcat-user.xmlに以下を追記します。

ブラウザでの動作検証

上記の状態でサーバを起動し、ブラウザからリソースにアクセスします。まずはpublicにアクセスします。
http://localhost:8080/JerseyAuth/webapi/public/info

認証なしで、以下のデータが返却されます。

次はprivateにアクセスします。
http://localhost:8080/JerseyAuth/webapi/private/info

FORMの認証画面が表示されました。ちゃんとアクセス制限が効いています。ここでuser1/passwordを入力し、ログインすると、以下のデータが返却されます。

後はクライアント側で何とかすれば認証ありでリソースを使うことができます。

jQueryで$.getJsonを使ってデータを取れば良いと思います。HTMLも認証ありのディレクトリに突っ込んでおけばいいですし、HTMLページを介さないで直接上記リソースにアクセスされても認証があるので大丈夫でしょう。

ブラウザ以外(Javaコード)での動作検証

クライアントがブラウザでない、例えばAndroidとかでも大した違いはありません。ここではApache HttpComponentsのHttpClientを使って、Android側から通常のJavaコードでリソースにアクセスすることを考えます。JerseyClientというものもあって、そっちも便利なんですがCookie周りなど状態に関する扱いが不便なので、今回はApacheの方を利用します。

では実際にコードを作成してアクセスしてみます。ここではMainクラスに書いて通常のJavaアプリケーションとして動作させますが、Androidの場合は適宜AsyncTaskLoaderとかに書いてください。

実行結果(publicなリソース)

実に簡単ですね。ライブラリ万歳です。JSON.decodeはJSONICというライブラリで、これを使ってJSONの文字列をJavaオブジェクトに変換しています。publicのリソースは問題なく取得できました。ちなみにentityは内部にStreamを持っているので、必ずCloseしてください。でないとリークします。Closeが面倒だという人はEntityUtils.consumeを実行しましょう。内部でCloseしてくれています。

さて、問題はprivate、つまり認証ありの方です。

実行結果(privateなリソース、認証なし)

なんと残念なことに3回GETまたはPOSTを発行する必要があるようです。自分のやり方がまずい気もします。初めのGETはサーバ側のセッション作成をログイン後にすれば減らせるかも・・・?

1回目のGETでCookieつまりJSESSIONIDを貰い、2回目でj_security_checkに対してログインをリクエストし、3回目で希望のリソースを取得します。2回目ではHTTP 302が返ってきており、ヘッダのLocationにアクセス先が記述されています。(上記ではもう分かり切ってるのでLocationの値を取ることはしていません。)302が返ってくるために、3回目で再度GETする必要がある、ということです。ここでようやくHTTP 200 OKでJSON文字列が取れます。

以上で終了です。FORM認証は上記のように3回リクエストする必要があったり、パスワード管理にハッシュとストレッチングが使えるか謎だったりで、まだまだ調べなくてはいけませんが・・・。とりあえずRESTで認証が可能なことが分かりました。

 - Java , ,