at posts/single.html

はてな認証APIかフォーム認証で tDiary にログイン

先月末に公開した tDiary の認証プラグイン (厳密にはコアを拡張しているのでプラグインじゃない) に手を加えて、 HTML フォームでも認証できるようにした。 先日の Ruby カンファレンスでも、 Basic 認証以外に対応しないんですか?って質問が出ていたしね。

極力、コアに手を入れないように作ってみたけど、どうだろう。

できること

  • はてな認証API を使ったログイン
  • HTML フォームを使ったログイン (ID/パスワード認証)
  • ゲストユーザと管理ユーザの区別 (管理ユーザのみ日記の編集を許可)

まだできないこと

  • ゲストユーザだけにツッコミを許可する
  • 設定画面からのユーザ管理
  • 設定画面からの初期設定

サンプル

サンプルを設置しました。管理者ユーザでログインして日記を編集できます。

http://www.machu.jp/sample/tdiary-auth/

ダウンロード

最新開発版の tDiary (2.1.4) が必要です。

インストール

アーカイブを展開すると、以下のファイルが生成されます。

index.rb
update.rb
tdiary.conf.auth
tdiary/auth.rb
tdiary/auth_hatena.rb
tdiary/auth_form.rb
plugin/03auth.rb
skel/login.rhtml
misc/mkpasswd.rb

これらのファイルを、最新開発版の tDiary (2.1.4) に上書きしてください。 次に、 tdiary.conf.auth を参考にして tdiary.conf を編集します。

@options['author'] = ['admin']

@options['form_auth'] = {
        'guest' => '49327:c028285dd70368dbf061bd47ddf9c9dd',
        'admin' => '859091:6f9ea824fe1549fe502ce62f0e64d582',
}

# require 'tdiary/auth_hatena.rb'
# @auth_class = TDiary::AuthHatena
@options['hatena_auth'] = {
        :api_key => 'input your api_key',
        :secret => 'input your secret'
}

@options['form_auth'] は HTML フォーム認証用の設定です。 ユーザ名とパスワードの対で構成されています。 パスワードは salt と生パスワードのハッシュ値を : で連結したものです。 パスワードのフォーマットを Ruby で表現するとこのようになります。

digest = Digest::MD5.hexdigest(salt + plain)
"#{salt}:#{digest}"

misc/mkpassrd.rb を使うと、簡単にパスワードフォーマットを生成できます。

@options['hatena_auth'] ははてな認証 API を使うための設定です。 設定ファイルにははてな認証 API のページで取得した API キーと秘密鍵を設定してください。 また、はてな認証 API のページで設定するコールバック URL には、あなたの日記のトップページの URL を設定してください。

@options['author'] は管理者ユーザ (日記の編集を許可するユーザ) を記述します。 はてな認証 API を使う場合は、はてなユーザ名の後ろに @hatena.ne.jp を付けて下さい。

新しい認証方式への対応

認証部分は別クラスに分離しているので、 TypeKey や OpenID への対応も容易にできると思います。

  1. 認証クラス (例, AuthTypeKey) を作り、 tdiary/autn_typekey.rb として配置する
  2. tdiary.conf に以下の設定を記述する。
require 'tdiary/auth_typekey.rb'
@auth_class = TDiary::AuthTypeKey

参考

index.rb と update.rb への差分は以下のとおり。 TDiaryLogin への分岐を追加しているだけ。

Index: update.rb
==================================================================
--- update.rb   (revision 2679)
+++ update.rb   (working copy)
@@ -16,13 +16,16 @@
        end
        $:.unshift( org_path.untaint )
        require 'tdiary'
+       require 'tdiary/auth'

        @cgi = CGI::new
        conf = TDiary::Config::new(@cgi)
        tdiary = nil

        begin
-               if @cgi.valid?( 'append' )
+               if !conf.session
+                       tdiary = TDiary::TDiaryLogin::new( @cgi, 'login.rhtml', conf )
+               elsif @cgi.valid?( 'append' )
                        tdiary = TDiary::TDiaryAppend::new( @cgi, 'show.rhtml', conf )
                elsif @cgi.valid?( 'edit' )
                        tdiary = TDiary::TDiaryEdit::new( @cgi, 'update.rhtml', conf )
Index: index.rb
===================================================================
--- index.rb    (revision 2679)
+++ index.rb    (working copy)
@@ -16,6 +16,7 @@
        end
        $:.unshift( org_path.untaint )
        require 'tdiary'
+       require 'tdiary/auth'

        @cgi = CGI::new
        conf = TDiary::Config::new(@cgi)
@@ -27,7 +28,11 @@
        end

        begin
-               if @cgi.valid?( 'comment' ) then
+               if @cgi.valid?( 'login' ) then
+                       tdiary = TDiary::TDiaryLogin::new( @cgi, "login.rhtml", conf )
+               elsif @cgi.valid?( 'logout' ) then
+                       tdiary = TDiary::TDiaryLogout::new( @cgi, "logout.rhtml", conf )
+               elsif @cgi.valid?( 'comment' ) then
                        tdiary = TDiary::TDiaryComment::new( @cgi, "day.rhtml", conf )
                elsif @cgi.valid?( 'date' )
                        date = @cgi.params['date'][0]

ToDo

自分用のメモです…。

  • ログインするまでセッション Cookie を発行しない
  • はてな認証APIへのリクエスト生成時に無条件で全てのパラメータに署名している
  • 日記の編集画面がクライアントのキャッシュに残る
  • HTML 認証でログイン失敗時にエラーメッセージが表示されない

関連する日記