はじめに
前回まで、Curl ORBを用いたJavaサービスへのアクセス方法について、いろいろと説明してきました。今回は、ほとんどのエンタープライズ・アプリケーションに必要な認証とアクセス制御の実装方法について説明したいと思います。
これまでの記事
概要
多くの認証とアクセス制御は以下のような仕組みになると考えられます。
ログインサービスでログイン認証を行い、ログイン成功であれば、サービスA、B、Cにアクセスできるようになります。もし、ログインしていない場合やログイン失敗した場合は、サービスA、B、Cにアクセスできないようになります。これをSpring Frameworkと組み合わせて、実現する方法を説明していきたいと思います。
まず、以下の3つのライブラリ(jarファイル)をダウンロードして、Curl ORBのサーバサイドに追加してください(前回までの記事で追加されたものは既に追加されてあるものとします)。
ログインサービス
ここでは、ユーザーIDとパスワードを渡し、成功か否かを結果として返す簡単なサンプルを紹介します(実際のプロジェクトでは、ここに認証のロジックをコーディングしてください。また、暗号化などにも考慮してください)。以下は、ログインサービスとユーザー情報のサンプルです。
package sample; import javax.annotation.Resource; import org.springframework.stereotype.Service; import com.curlap.orb.security.RemoteService; /* ログインサービス */ @RemoteService @Service("login") public class LoginService { @Resource private UserInfo userInfo; /* ログインメソッド */ public boolean login(String userId, String password) { if (userId.equals("user01") && password.equals("pass")) { userInfo.setUserId(userId); userInfo.setHasLogined(true); //trueをセット return userInfo.isHasLogined(); } return false; } }
package sample; import java.io.Serializable; /* ユーザー情報 */ public class UserInfo implements Serializable{ private static final long serialVersionUID = 1L; private String userId; private boolean hasLogined; public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public boolean isHasLogined() { return hasLogined; } public void setHasLogined(boolean hasLogined) { this.hasLogined = hasLogined; } }
このサンプルの認証ロジックは、単純にユーザーID:user01、パスワード:passであればtrueを返すものとなっています。ログインに成功した場合、LoginServiceのフィールドであるUserInfoのhasLoginedにtrueをセットします。また、このUserInfoはセッションごとに作成されるようにするため、Springの設定ファイル(applicationContext.xml)に以下の行を追加し、スコープをsessionとして管理できるようにします。
<bean id="userInfo" class="sample.UserInfo" scope="session"> <aop:scoped-proxy/> </bean>
アクセス制御
次に作成したUserInfoを用いて、アクセス制御機能を追加していきます。ここでは、ログインに成功した場合のみ以下のSecureServiceサービスにアクセスできるようにします。
package sample; import org.springframework.stereotype.Service; import com.curlap.orb.security.RemoteService; @RemoteService @Service("secure") public class SecureService { public String doSomething() { return "Did something!!"; } }
このSecureServiceには、ログイン済みの場合にはアクセス可能、未ログインの際にはアクセス不可という制御をかけることにします。こういった処理は通常SecureServiceだけではなく、多くのサービスを制御することとなるため、AOPを使い共通機能として作っていきます。
AOPを使って各メソッドの実行前にアクセスチェック機能を設けるため、MethodBeforeAdviceを継承したクラスを作成し、beforeメソッドを実装します。
package sample; import java.lang.reflect.Method; import javax.annotation.Resource; import org.springframework.aop.MethodBeforeAdvice; public class ServiceBeforeAdvice implements MethodBeforeAdvice { @Resource private UserInfo userInfo; public void before(Method method, Object[] args, Object target) throws Throwable { if (!userInfo.isHasLogined()) { throw new AuthException("Authentication error!!"); } } }
ここでは、UserInfoのhasLoginedがfalseであれば、ログインに成功していないこととなるので、AuthExceptionという例外をスローするようにします。もしhasLoginedがtrueであれば、ログインに成功していますので、SecureServiceのメソッドにアクセスできるようにします。
package sample; /* * AuthException * NOTE: extends RuntimeException due to AOP */ public class AuthException extends RuntimeException { private static final long serialVersionUID = 1L; public AuthException() { super(); } public AuthException(String message) { super(message); } public AuthException(String message, Throwable rootCause) { super(message, rootCause); } public AuthException(Throwable rootCause) { super(rootCause); } }
AuthExceptionは、RuntimeExceptionを継承したクラスです。
このServiceBeforeAdviceをSpringの設定ファイル(applicationContext.xml)に設定するため、以下の行を追加します。
<aop:config> <aop:advisor pointcut="execution(* sample.SecureService.*(..))" advice-ref="before"/> </aop:config> <bean id="before" class="sample.ServiceBeforeAdvice" />
もし、SecureService以外のサービスも追加するには上記のpointcutを修正してください。
これで、認証とアクセス制御の機能ができました。web.xmlに以下のリスナーを追加して、サーバを起動してください。
<listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener>
テスト実行
LoginService、AuthException、SecureServiceをCurl ORBのコード生成ツールで作成し、アクセスすると、ログインに成功しない場合はAuthExceptionが発生し、ログインに成功した場合はSecureServiceサービスにアクセスできます。Curl ORBのコード生成ツール利用方法は前回の記事を参考にしてください。以下がサンプルコードとなります。
|| ログイン失敗 def login-service = {LoginService} {login-service.login "no user", "no pass"} || falseが返ってくる def secure-service = {SecureService} || bind-exceptionプロシージャでAuthExceptionを登録しておくと、以下の行でAuthExceptionが発生する {secure-service.do-something} || セッションをクリア {clear-jsessionid-in-cookies} || ログイン成功 {login-service.login "user01", "pass"} || サービスも実行できる def str = {secure-service.do-something}
これで、認証とアクセス制御を確認することができます。
まとめ
今回はエンタープライズアプリケーションで必須なユーザ認証とアクセス制御の実装方法について解説しました。
これまで3回の連載を通じて説明したように、Curl ORBとSpring Frameworkを用いることで、バイナリ形式の高速データ通信やサーバサイドJavaとの容易な連携ができることをご理解頂けたのではないでしょうか。
RIAの採用はリッチなユーザーインタフェースや優れた操作性などをユーザに提供できますが、サーバサイドまでをシームレスに繋ぎ、より高速なパフォーマンスを実現するには、Curl ORBの仕組みがエンタープライズRIAでは必要だと考えています。
Curl ORBはSpring Frameworkだけでなく、Seasar2などとも連携できます。実装方法やサンプルソースはCurlのデベロッパーセンターで公開していますので、ご興味を持っていただけた方はぜひデベロッパーセンターを覗いてみてください。