やってみようpart6(JDBCRealm)
先に書いたとおり、認証はSAStrutsのサンプルでもあるとおりJ2EEコンテナにまかせることにしました。id:higayasuoさんおすすめらしいです。
テーブルの準備
まず、DBの準備です。ユーザテーブルにはユーザIDとクレデンシャル(パスワード)、ロールテーブルにはユーザIDとロール名があることが大前提のようです。
こまかいことを言うと、ユーザテーブルのキーはidなので、ロールテーブルにもidを外部キーとして持ちたい気分になりますが、そこはそれ、画面から入力される文字列がここでいうIDになるので、ここではlogin_idをロールテーブルに外部キーとして持たせています。
server.xmlの設定
えーっと、Tomcat前提です。
すでにserver.xmlにJDBCRealmの設定がコメントされていますのでそれ参考で。以下抜粋です。
上のテーブル構成だとこんな感じになりました。
<Realm className="org.apache.catalina.realm.JDBCRealm" connectionName="dbuser" connectionPassword="dbpass" connectionURL="jdbc:mysql://hostname/dbname" driverName="com.mysql.jdbc.Driver" roleNameCol="role" userCredCol="passwd" userNameCol="login_id" userRoleTable="roles" userTable="users" />
サンプルだとドライバーのクラスが org.gjt.mm.mysql.Driver になっていますがどうなんでしょう。ぼくはjdbc.diconにあわせました。ちゃんと動いてるからこれでいいんでしょう。
追記:
デフォルトで有効になっているUserDatabaseRealmはコメントアウトしましょう。(2008.6.26)
<!-- コメントアウトしましょう <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/> -->
web.xmlの設定
<security-constraint> <web-resource-collection> <web-resource-name> Authentication </web-resource-name> <url-pattern>/schedule/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>user</role-name> <role-name>admin</role-name> </auth-constraint> </security-constraint> <security-role> <role-name>user</role-name> </security-role> <security-role> <role-name>admin</role-name> </security-role> <login-config> <auth-method>FORM</auth-method> <form-login-config> <form-login-page>/WEB-INF/view/login/login.html</form-login-page> <form-error-page>/WEB-INF/view/login/loginError.html</form-error-page> </form-login-config> </login-config>
です。
おおきく、
にわけることができます。
- このアプリケーションで有効にするロールの定義。つまりはロールテーブルのroleカラムにはいる値そのもの。ちなみに、どうしたって
<!-- NG --> <security-role> <role-name>user</role-name> <role-name>admin</role-name> </security-role>
こう書きたくなるんだけど、これはNGのようです。
アクセス制限対象URL(複数可) アクセスが許可されるロール(複数可)
現段階ではまだ設定してないですが、実際には、/manage/*以下はadminロール、/schedule/*以下はadmin or userとしたいので、
認証方法(FORM)と認証のかかっているURLにアクセス時に遷移する画面(
認証方法をBASICにしたら、そもそも認証画面とかエラー画面の指定はいらないような気がしてきた。まあいいや。
その認証画面
url | /j_security_check |
---|---|
ログインIDのname属性 | j_username |
パスワードのname属性 | j_password |
以下、抜粋。
<form method="post" action="../j_security_check"> <table class="login"> <tr> <th>ログインID</th> <td><input type="text" name="j_username" value="" size="10" /></td> </tr> <tr> <th>パスワード</th> <td><input type="password" name="j_password" value="" size="10" /></td> </tr> <tr> <td colspan="2" style="text-align:center; padding-top:15px"> <input type="submit" name="login" value="ログインする" /> </td> </tr> </table> </form>
認証成功
認証に成功したら「誰がログインしたのか」をアプリが認識する必要があります。
当たり前ですが、servlet APIに準備されてます。
@Execute(validator = false) public String index() { Principal userPrincipal = request.getUserPrincipal(); logger.debug("LoginUser is " + userPrincipal.getName()); User user = userService.getUserDto(userPrincipal.getName()); Beans.copy(user, userDto).execute(); : }
って感じです。
よくよく考えるとこのweb.xmlの設定では、/schedule/ 以下だとなんでもかんでも認証がかかるわけなので、index()だけにユーザ情報取得処理をいれててもあかんのか。/schedule/hogeにアクセスされるとhoge()にいっちゃう?
それこそAOPで横断的になんとかできないかな。
今日はここまで。
追記:
http://d.hatena.ne.jp/ngtn/20080603/1212503018
こちらにも詳しく書かれています。
(2008.6.26)