読者です 読者をやめる 読者になる 読者になる

Wicketの認証機能

概要

前回Wicketに認証機能を追加しようとしてSpring Securityを導入してみたのですが、そもそも方向性が間違っていました。Wicketには、wicket-auth-rolesという認証機能のサブプロジェクトがあります。

情報源

Wicket公式サイトwicket-auth-rolesの情報を探したのですが、見つかりませんでした。公式サイトからリンクされているWikiにあるかも知れませんが、現在(2010/04/13)メンテナンス中でアクセスできない状態です。


ソースは、Apachiのsvnにそれらしきリリースタグのブランチがありました。
mavenのセントラルリポジトリに見当たらないため、svnリポジトリから直接入手するしかなさそうです。
http://svn.apache.org/repos/asf/wicket/releases/wicket-1.4.7/wicket-auth-roles


また、examplesディレクトリに、wicket-auth-rolesのサンプルがあります。
http://svn.apache.org/repos/asf/wicket/releases/wicket-1.4.7/wicket-examples/src/main/java/org/apache/wicket/examples/authentication


さらに、下記サイトを参考にさせていただきました。
rio's blog
Wicket の勉強 (4) wicket-auth-roles を使って認証/認可を実現する」
http://rio1218.blog26.fc2.com/blog-entry-82.html



サンプル

svnのexamplesを元に、既存のWicketアプリケーションに「最小限の認証機能」を分かる限り最短で導入する手順を紹介します。

1.pom.xmlwicket-auth-rolesを追加

<dependency>
  <groupId>org.apache.wicket</groupId>
  <artifactId>wicket-auth-roles</artifactId>
  <version>1.4.7</version>
</dependency>


2.AuthenticatedWebSessionの導入
AuthenticatedWebSessionを継承した新規クラスを追加します。

import org.apache.wicket.Request;
import org.apache.wicket.authentication.AuthenticatedWebSession;
import org.apache.wicket.authorization.strategies.role.Roles;

public final class MyAuthenticatedWebSession extends AuthenticatedWebSession {

	private static final long serialVersionUID = 1L;

	public MyAuthenticatedWebSession(Request request) {
		super(request);
	}

	@Override
	public boolean authenticate(final String username, final String password) {
		return username.equals("wicket") && password.equals("wicket");
	}

	@Override
	public Roles getRoles() {
		if (isSignedIn()) {
			return new Roles(Roles.ADMIN);
		}
		return null;
	}

}

3.AuthenticatedWebApplicationの導入
Applicationクラスの継承元をWebApplicationから、AuthenticatedWebApplicationに変更

import 既存のインポートクラス・・・
import org.apache.wicket.authentication.AuthenticatedWebApplication;
import org.apache.wicket.authentication.AuthenticatedWebSession;
import org.apache.wicket.authentication.pages.SignInPage;

public class FooApplication extends AuthenticatedWebApplication {

	@Override
	protected void init() {
		super.init();
		既存の実装・・・
	}

	@Override
	public Class<? extends Page> getHomePage() {
		既存の実装・・・
	}

	@Override
	protected Class<? extends WebPage> getSignInPageClass() {
		return SignInPage.class;

	}

	@Override
	protected Class<? extends AuthenticatedWebSession> getWebSessionClass() {
		return MyAuthenticatedWebSession.class;
	}
}

4.@AuthorizeInstantiationの導入
ログインしないと遷移できないページのクラスに@AuthorizeInstantiationアノテーションを追加
@AuthorizeInstantiation("ADMIN")

 @AuthorizeInstantiation("ADMIN")
 public class AdminPage extends BasePage {
  ・・・

結果

上記例では、未ログインの状態でAdminPageに遷移すると、自動的にログイン画面に当たるSignInPageが開きます。
ここで、ユーザ名="wicket"、パスワード="wicket"を入力しないと先に進めません。


補足説明

  • 今回はログイン画面として、組み込みのSignInPageを使用していますが、本来はこのクラスを継承した独自のPageを作成する必要があります。
  • MyAuthenticatedWebSession#authenticate(String,String)では、オンコードで判定を行っていますが、実際はここでDB等からユーザ情報を取得する必要があります。
  • MyAuthenticatedWebSession#getRoles()でisSignedIn()を使用してログイン判定をしていますが、スーパークラスのAuthenticatedWebApplicationでauthenticate()の戻り値をsignedInフィールドに保持しています。
public final boolean isSignedIn() {
    return signedIn;
}
public final boolean signIn(final String username, final String password) {
    return signedIn = authenticate(username, password);
}
  • 今回は、getRoles()でオンコーディングでRoles.ADMINを返していますが、ログインユーザによりロールを変える場合は、authenticate()でユーザ情報をセッション内に保持し、getRoles()内でユーザ情報から判定する必要があります。

その他

  • trunkのAuthenticatedWebSessionのインタフェースにauthenticate(String,String)が無い。将来は実装が変る?
  • IAuthorizationStrategyを使用すればWicket単体でも認証機能が導入できそう。wicket-auth-rolesを使うほうが多分簡単。
  • Wicketのexamplesは非常に多くのパッケージがあり、今回使用したauthenticationは他のサンプルに依存しているため、動作未確認。

 今回は、examplesのソースを元に手元のテストアプリを拡張して動作確認した。