Make組ブログ

Python、Webアプリや製品・サービス開発についてhirokikyが書きます。

WSGI向け認証フレームワーク、repoze.whoを使ってみた

WSGI向け認証フレームワーク、repoze.whoを使ってみた

repozewwho というWSGI用の認証フレームワークがあります。

Webアプリケーションを書くうえでユーザー認証はほぼほぼ必須となりますが、 それを提供してくれる素晴らしいものです。

なかなかよくできたやつなのですが、分かるまでが分かりにくいです。 repozewwho がどんなものか、どう使うのかを中心に、 理解への助けになるものをまとめておこうと思います。

pyhack 36 でやってたことです。

repoze.whoで何ができたか

WSGIでWebアプリケーションを作る際になどに、認証の枠組みを提供できます。

実際に今作っている WeiWei という(WSGIベース、つまりWebフレームワークなしで作っている) Wikiエンジンで導入してみました。 これがその変更点なのでこれをパクれば導入できます:

導入できたものは「WSGIアプリケーションが401を返したときにBasic認証を促し、 入力された場合は入力が何であれ認証を許可する」もの。 (WSGIミドルウェアとして repozewwho を設定しています)

ここで注意すべきなのは、この変更点では「利用者の入力が正当なものか」の検証はしていないということ。 実際の認証処理は SillyPlugin が担当しているけど、ここではユーザーの入力があればとりあえず「認証OK!!!」としています。 (Sillyなんです)。 この変更点はあくまで repozewwho の導入であり「ユーザーの入力が正しいかどうか」を判定する処理は 書いていない。

言ってしまうと repozewwho はそんなものを提供するものじゃないです。

repoze.whoって何よ

repozewwhodjango.contrib.auth のような「なんかユーザーモデルとかあるやつ」じゃないと分かったところで、 repozewwho とは何なのよ。

簡単に言うと「単なる枠組み」。 そこに付随する処理(例えば上記した、実際の認証をする'Authenticator')を自分たちで プラグインとして提供できます。 repozewwho 自体が提供するプラグインもあるけど、根幹としてある repozewwho は枠組み/ 流れのみを提供してくれるものです(美しい)。

repozewwhoプラグインを差し込む場所として提供しているのは以下4点:

  • Identifier: 認証情報を取り出す部分
  • Authenticator: 認証を実際にする部分
  • MetadataProvidor: 認証時に取れた付加情報を追加する部分 (今回は使ってない)
  • Challenger: 認証を促す部分

その差し込んだプラグインが、 repozewwhoWSGIミドルウェアとして使うことで適宜呼び出されて いきます(repozewwho が提供するAPIで明示的に呼ぶこともできますヾ(´∀`)ノキャッキャ)。

それぞれの説明は、 repozewwho コントリビューターでもあるaodagさんのブログ記事も参考に なります。

使ったプラグインとその説明

今回使ったプラグインと、 repozewwho の実際の動きについて少々。

今回の場合は以下のプラグインを使いました:

  • Identifier: basicauth (repoze.who提供)
  • Authenticator: silly (自前の仮置き)
  • Challenger: basicauth (repoze.who提供)

Identifierとしてのbasicauth

Basic認証から認証情報(identity)をとりだします。 identity[‘login’]とidentity[‘password’]からクライアントの入力をとれます (このidentityは例えばAuthentiatorなどで使われる)。

Challengerとしてのbasicauth

クライアントに対してBasic認証をさせるヘッダを送信する。

他のChallengerとしてはredirectorなどがあり、ログイン画面にリダイレクトさせたりできます。

Challengerの発火

ちらっと説明したように、Challengerが発火するタイミングは 「 repozewwho 配下のWSGIアプリケーションが401を返したとき」としています。

この挙動はwho.iniに記述したgeneralセクションの challenge_decider による挙動で、そこは適宜変更できます。

今回の場合はloginを担当するWSGIアプリケーションから「ユーザーがログインしていなければ 401を返す」ようにしてChallengerを呼び出させています。 が、やりかたとしてはあんまり賢くないですね。今後改良することになりそうです。

(余談: login_viewはDjango/Pyramidのviewと同じ立ち位置のもので、WSGIアプリケーションとしてはweiwei.web.login_dispatchというものが担当しています。これは WeiWei の実装の話です)

サードパーティプラグイン

プラグインとしては優秀そうなものがいくつかありますが、あまりメンテされてない印象。 たいていのものは repoze.who 1.0 系にのみ対応したものになるならしい。 以下の3つはなかなか優秀そうであるけど、repoze.who 2系に対応してないくさいとか Python 3系に対応してないとかで使用しなかったものです:

  • repoze.wo_sqlalchemy :バックエンドをSQLAlchemyとしてUserModelとかをうまく扱ってくれるっぽい(UserModel!!)
  • repoze.what: 認証したうえでの権限の扱いなどをしてくれるものっぽい
  • repoze.who-use_beaker : repozeが提供する認証を保持するauth_tktというプラグインCookieベースでいけてないので、それをbeaker (セッション)でやろうというもの。

まぁ使いたければメンテしてやるか参考にして自分で作ればいいです。

repozewwho は美しい(プラグインを基本としてその枠組みのみ提供するとこが良い)ですが、 どうにもプラグインとして外部に提供させると使う側としては選別が面倒になりますね。

さっき書いたSillyPluginではあまにり滑稽なので、その後にちゃんとUserモデルを使った 認証を WeiWei では書いています

まぁ自分でプラグインを書いていきましょう。

まとめ

結局 repozewwho とは、認証の流れを提供するだけのものでした。 プラグインを開発者が提供して初めて期待する「認証」ができます。 repozewwho は .ini. の記述によるプラグイン設定、zope.interfaceによるプラグインの実装 など非常に美しいものでした。

「ユーザーモデルとかあってDBに保存するもの欲しい」という人はプラグインを探すか 自分で書くか、WSGIだけというのは諦めて優秀なWebフレームワークのDjangoとかを使いましょう。