日々のすきをみてドン亀のごときペースで Haskell の勉強をしているのですが、入門書片手に学ぶのも飽きてきたので、実際になんか作ってみようとしています。
そこで Haskell の Web アプリケーションフレームワーク「Yesod」に挑戦しています。
Yesod はデフォルト状態(プロジェクトを作成直後の状態)ですでにログイン認証の仕組みが使えるようになっているのですが、この認証方式が Google の仕組みを使う一種のシングルサインオン方式になっているのです。これはこれで技術的に興味深いのですが、しかしじゃあ実際にどれぐらい使うんだというと、実案件ではそうそう使うものではないと思います。実際によく使う方式といえばやはり DB にユーザ名とパスワードを保存しておき、入力値がそれにマッチするかを見る方式が多いのではないでしょうか?
Yesod には標準で Yesod-Auth という認証の仕組みがあって、このサブパッケージによって前述の Google を使った認証方法や BrowserID を使った認証方法など様々な認証方法を提供しています。そして当然 DB を使った認証方法も提供しています。それが Yesod.Auth.HashDB パッケージ(以下 HashDB)です。
しかし、これを使うためのドキュメントでわかりやすいのがなかなか見つからないのです! 英文のリーディング自体がたどたどしい Haskell と Yesod の初学者にはイバラの道以外の何物でもないような状態だと私は感じました。しかしなんとか最低限何をすればいいのかまとめることができましたので紹介します。
なお、今回使用した Yesod のバージョンは 1.2.3.3 です。この記事に関するソースコードは Github で公開しています。diff を見てみるとどこに手を付けたのかわかりやすいかもしれません。
手を付けるべきファイルは3つ
そもそもデフォルトの状態から最低どのファイルに手をいれるべきかもなかなか定かにならなかったのですが、以下の3つが修正対象です。
- config/models
- Models.hs
- Foundation.hs
config/models
まず、デフォルトでもユーザ情報を格納するためのテーブル定義を行っているのですが、HashDB で使用するには若干手直ししなければなりません。ポイントは以下の点です。
- パスワードは必須項目でなければなりません。
- salt カラムが必要です。
デフォルトでは password カラムに Maybe がついているのでパスワードが必須項目になっていません。また、HashDB ではパスワードは SHA-1 でハッシュ化して扱います。その際に salt の値を使います。具体的な例をあげると、パスワードが “secret”、salt が “shio” だとすると “shiosecret” をハッシュ化した値を使用するわけです。この salt を保存するカラムが必要になります。
以上を踏まえると、config/models の User 定義は以下のようになります。
1 2 3 4 5 6 | User ident Text password Text salt Text UniqueUser ident deriving Typeable |
Model.hs
config/models の定義によってモデルが User 型が定義されますが、HashDB で使用するには HashDBUser 型クラス制約を満たさなければなりません。それのための修正を Model.hs で行います。まず、HashDB を Import します。
5 | import Yesod.Auth.HashDB (HashDBUser(..)) |
次に型インスタンスの作成です。
17 18 19 20 21 22 | instance HashDBUser User where userPasswordHash = Just . userPassword userPasswordSalt = Just . userSalt setSaltAndPasswordHash s h p = p { userSalt = s , userPassword = h } |
Foundation.hs
最後の Foundation.hs で認証方式を設定します。まず、BrowserID 認証方式と GoogleEmail 認証方式を使用しないので、以下の Import は削除してかまいません。
7 8 | import Yesod.Auth.BrowserId import Yesod.Auth.GoogleEmail |
かわりに HashDB のための Import を追加します。
7 | import Yesod.Auth.HashDB (authHashDB, getAuthIdHashDB) |
getAuthId と authPlugins を修正します。
124 125 126 127 | getAuthId = getAuthIdHashDB AuthR (Just . UniqueUser) -- You can add other plugins like BrowserID, email or OAuth here authPlugins _ = [authHashDB (Just . UniqueUser)] |
以上で完了です。
その他、使い方等は Github にあげている readme.md を参照してください。