最近
最近は忙しい。
そして、今日は応用情報技術者試験だった。
結果は多分駄目だろう。
10月こそは絶対とる。
とりあえず試験は終わったから、最近興味があるJavaScriptを勉強しなおす。
http://openlab.dino.co.jp/category/workshop/ws_javascript
DINOさんの勉強会の資料と内容はホント分かりやすい。
プロジェクトの自動ビルド
Hot Deploy が機能しなかったり、なんかEclipseおかしいなと思ってたら、プロジェクトの自動ビルドのチェックが外れてた...。
通りでCleanしないと、うまく動かないわけだ。
Cleanの下にあるから間違って、クリックしちゃったんだと思う。
Subversionでバージョン管理したくないファイルの設定について
Subversionでバージョン管理したくないファイルが有る場合はsvn:ignore属性を追加します。
EclipseでSubversiveプラグイン使ってsvn:ignore属性を追加してたのですが、どこにどういう設定ファイルができるとか仕組みがいまいちわからないまま使っていたので、ちょっと調べてみました。
Subversiveプラグイン
svn:ignore属性を追加する
1.Eclipseからバージョン管理したくないファイルを右クリックして、[team]->[Add to svn:ignore...]を選択します。
2.コミットします。
作成されるファイル
.svnディレクトリに dir-prop-base というファイルが作成されます。多分、[Add to svn:ignore...]を選択したときに作成されるファイルだと思います。ファイルを確認してみると。次のようになっています。
K 10
svn:ignore
V 57
target.tomcatplugin
.settings
repo
work
END
.settingディレクトリ、targetディレクトリ、repoディレクトリ、workディレクトリ、.classpathファイル、.tomcatpluginファイルにadd:ignore属性を追加したのでそのようにファイルが作成されています。
ハイフン(-)付のデータベース名を作成する
できないと思ってたら、できたので書いておく。
PostgreSQL 8.1.11
失敗
postgres=# CREATE DATABASE x-xxxdb;
ERROR: syntax error at or near "-" at character 18
LINE 1: create DATABASE x-xxxdb
成功
postgres=# create DATABASE "x-xxxdb";
CREATE DATABASE
ダブルクォート(")で囲めば良いみたいですね。
MySQLでは、バッククォート(`)で囲むみたいですね。
MySQLで"-"(ハイフン)を含むデータベース名を付けたい場合 - 元RX-7乗りの適当な日々
サーブレットの認証を使わずに@Executeのroles属性を有効に使う方法
SAStrutsで認証を実装したいのですが、お勧めはサーブレットの認証機能を使って認証する方法みたいです。
今回はアプリケーションサーバがTomcatで、ユーザ情報はDBで管理したいのでJDBCRealmを使ってやろうかなと思っていました。
ところが、ログインの認証機能が複雑な仕様になってしまって、JDBCRealmでは実現できないことがわかりました。
何とか、@Executeのroles属性でメソッド単位に認証をかけたいと思って、調べました。
調査
そもそも、どのようにrolse属性に設定したロールで認証がかかっているのか?
また、会社にあったStruts in アクションに書いてあるんじゃないかと思って、ActionMappingのrolse属性を見てみました。
以下、抜粋。
セキュリティチェックは、RequestProcessorのprocessRoles()メソッドで処理されます。RequestProcessorをサブクラス化することにより、アプリケーションベースのセキュリティでもrolesプロパティを使用できます。
何かできそうだ!!
さらに、RequestProcessor#processRoles()を見てみると…。
String roles[] = mapping.getRoleNames(); if ((roles == null) || (roles.length < 1)) { return (true); } // Check the current user against the list of required roles for (int i = 0; i < roles.length; i++) { if (request.isUserInRole(roles[i])) { if (log.isDebugEnabled()) { log.debug(" User '" + request.getRemoteUser() + "' has role '" + roles[i] + "', granting access"); } return (true); } }
mapping.getRoleNames()でロール属性を取得して、request.isUserInRole()で検証している。
ということは…。
isUserInRole()メソッドをオーバーライドすればできる!?
実装
サーブレット仕様の認証を使わずにgetRemoteUserやisUserInRoleを使う。 - NullPointer's
まるっきり、実装方法が紹介されてました。
前提条件として、ユーザー情報*1はログイン処理後、セッションに保持する。
そして仕組みは
1.HttpServletRequestWrapperを継承して、isUserInRole()メソッドでセッションに保存してあるユーザー情報のロールを戻り値にする
2.フィルターで独自実装のHttpServletRequestを呼び出す。
という感じ。
AuthHttpServletRequest.java
package jp.co.suusuke.servlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpSession; public class AuthHttpServletRequest extends HttpServletRequestWrapper { /** * @param request */ public AuthHttpServletRequest(HttpServletRequest request) { super(request); } /* (non-Javadoc) * @see javax.servlet.http.HttpServletRequestWrapper#getRemoteUser() */ public String getRemoteUser() { HttpSession session = this.getSession(false); if (session == null) { return null; } return (String) session.getAttribute("auth.user"); } /* (non-Javadoc) * @see javax.servlet.http.HttpServletRequestWrapper#isUserInRole(java.lang.String) */ public boolean isUserInRole(String str) { if (str == null) { return false; } HttpSession session = this.getSession(false); if (session == null) { return false; } Object role = session.getAttribute("auth.role"); return (str.equals(role)); } }
AuthFilter.java
package jp.co.suusuke.servlet.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import jp.co.suusuke.servlet.AuthHttpServletRequest; public class AuthFilter implements Filter { /* * (non-Javadoc) * * @see javax.servlet.Filter#destroy() */ @Override public void destroy() { } /* * (non-Javadoc) * * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, * javax.servlet.ServletResponse, javax.servlet.FilterChain) */ @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { chain.doFilter( new AuthHttpServletRequest((HttpServletRequest) request), response); } /* * (non-Javadoc) * * @see javax.servlet.Filter#init(javax.servlet.FilterConfig) */ @Override public void init(FilterConfig arg0) throws ServletException { } }
web.xml
<filter> <filter-name>authFilter</filter-name> <filter-class>jp.co.suusuke.servlet.filter.AuthFilter</filter-class> </filter> ... <filter-mapping> <filter-name>authFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
フィルターの順番は先頭*2に設定したんだけど、いいのかな?
後で、デバッグしてみよう。
とりあえず、JDBCRealm使わないでroles属性を有効に使うことができた。
検証エラー時に、input先に遷移する前にリクエストに情報を設定する方法。
Seasarのメーリングリストで、質問されてました。
(Seasar-user:16966)
ひがさんより@Executeのinput属性にメソッドを指定してという返信があって、メソッド指定ができること知らなかったのでメモ。
どういうことか
例えば、アンケート入力画面が有って、アンケートの項目はActionクラスで動的に生成してRequestスコープに設定して画面表示している場合。検証エラー時(アノテーションでの)にアンケートの項目をどのように設定するのかということ。
今まで
@Executeアノテーションのvalidate属性に"@"と表示用のオブジェクトを作るメソッドを作って設定してました。
QuestionAction.java
public class QuestionAction { @ActionForm @Resource protected QuestionForm questionForm; public List<QuestionView> questionViewList; @Execute(validator = false) public String index() { // 表示処理(questionViewListの生成) return "index.jsp"; } @Execute(validator = true, validate="validate, @", input = "index.jsp") public String regist() { // 登録処理 return "regist.jsp"; } public ActionMessages validate() { // 表示処理(questionViewListの生成) return new ActionMessages(); } }
QuestionForm.java
public class QuestionForm { @Required public String[] questions; }
こうすればよかった
@Executeアノテーションのinput属性に表示用のオブジェクトを生成するメソッドを追加する。
QuestionAction.java
public class QuestionAction { @ActionForm @Resource protected QuestionForm questionForm; public List<QuestionView> questionViewList; @Execute(validator = false) public String index() { // 表示処理(questionViewListの生成) return "index.jsp"; } @Execute(validator = true, input = "backToIndex") public String regist() { // 登録処理 return "regist.jsp"; } @Execute(validator = false) public String backToIndex() { // 表示処理(questionViewListの生成) return "index.jsp"; } }
QuestionForm.java
public class QuestionForm { @Required public String[] questions; }