実行できるかのチェック
権限によって実行させたくないActionがある場合って、普通どういう風にコーディングするんだろ?
前は、抽象クラスのActionをつくって実装してた。
public abstract AdminServiceAction extends Action { protected ActionForward executeLogic(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { User logonUser = (User) request.getSession().getAttribute("logonUser"); if (logonUser != null && logonUser.isAdmin()) { return doExecute(mapping, form, request, response); } return mapping.findForward("deny"); } protected abstract ActionForward doExecute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception;
Tomcatとかの認証機能を利用して実装する方法もあるのかなー。でも知らない・・・勉強不足・・・
今回は、勉強をかねてInterceptorで実装してみた。
POJOのDipatchActionを利用してたので、メソッド単位で実行できるかをチェックするようにした。
こんな感じでInterceptorを作ってみた。2回目の作成だったからすんなり作れた記憶があるけど、今見ると気になる点が何箇所かある。まっいっか。
public class PermitServiceInterceptor extends AbstractInterceptor { private static final String DEFAULT_PERMIT = "DEFAULT_PERMIT"; private static final String PERMIT_SUFFIX = "_PERMIT"; // ----------------------------------------------------------------------- public String getKey() { return "role"; } public String getForward() { return "deny"; } // ----------------------------------------------------------------------- public Object invoke(MethodInvocation invocation) throws Throwable { String methodName = invocation.getMethod().getName(); Class actionClazz = getTargetClass(invocation); List allowRoles = getAllowRoles(actionClazz, methodName); if (isPermit(allowRoles, getRole())) { return invocation.proceed(); } else { return getForward(); } } private List getAllowRoles(Class clazz, String methodName) { BeanDesc beanDesc = new BeanDescImpl(clazz); String fieldName = methodName + PERMIT_SUFFIX; if (beanDesc.hasField(fieldName)) { Field field = beanDesc.getField(fieldName); return AnnotationConfigUtil.getParameterList(field); } else if (beanDesc.hasField(DEFAULT_PERMIT)) { Field field = beanDesc.getField(DEFAULT_PERMIT); return AnnotationConfigUtil.getParameterList(field); } return new ArrayList(); } private String getRole() { S2Container container = SingletonS2ContainerFactory.getContainer(); HttpServletRequest request = container.getRequest(); return (String) request.getSession().getAttribute(getKey()); } private boolean isPermit(List allowRoles, String role) { if (allowRoles.contains("ALL")) { return true; } return allowRoles.contains(role); } }
嫌な点は、権限の確認を文字列の比較で行っているところ。
だから、logonの処理で
request.getSession().setAttribute("role", logonUser.getRole().toString());
とかして、sessionにRoleの文字列を設定する必要がある。
かっこわるい。
最初はメソッドごとにスタティック変数アノテーションを記述してたんだけど、だんだんメンドくさくなってきて、DEFAULT_PERMITってのを作った。
結局、Actionインターフェースにこんな風に、
public interface AuthAction { public static final String DEFAULT_PERMIT = "ALL"; /** * ログオンする */ public String logon(); /** * ログオフする */ public String logoff(); /** * 他のユーザーになりかわる。 */ public String transform(); public static final String transform_PERMIT = "ADMIN"; }
それで、DICONファイルをこんな感じで記述すれば、完成。
<components> <include path="aop.dicon"/> <component name="permitServiceInterceptor" class="study.xxx.extention.struts.interceptors.PermitServiceInterceptor"/> <component name="actionInterceptorChain" class="org.seasar.framework.aop.interceptors.InterceptorChain"> <initMethod name="add"><arg>aop.traceInterceptor</arg></initMethod> <initMethod name="add"><arg>permitServiceInterceptor</arg></initMethod> </component> <!-- action --> <component name="/auth" class="study.xxx.party.web.impl.AuthActionImpl" instance="prototype"> <aspect>actionInterceptorChain</aspect> </component> </components>
権限の確認はもっと動的にできても良いと思うけど、この程度で十分のときもあると思うから、これはこれでありかもね。って思った。
Interceptorを作る勉強としてはちょうど良かったなー。
っていうか、これは独自のスタティック変数アノテーションのつくり方の勉強だったのかも。終わってから思ったけど。
うーむ。もっときれいに作れそうな気がしてきた。
少し見直してみよっと。
そういえばJ2SE5.0のアノテーションってどんな感じなんだろう。
ふーん。インターフェースみたいに定義するんだー。
じゃぁ、S2Daoを参考にしてインターフェースを使えばいいのができるかも。
public interface Permit { public String TARGET = "METHOD"; public String SUFFIX = "PERMIT"; public List getValue(); }
って感じのインターフェースを作って、
String methodName = invocation.getMethod().getName(); Class clazz= getTargetClass(invocation); Permit permit = (Permit) AnnotatilUtil.getMethodAnnotationClass( Permit.class, clazz, methodName);
とするみたいなのかなー
っていうかこんな風に作る意味があるのか?
明日になってから作ることにしよう。ほかのいい案が出るかもしれないし。