目前项目使用的是Struts2+Hibernate+Spring的架构模式,目前已经有一套针对SSH2的权限系统,运行良好。但是项目有了新需求:在目前系统的基础上使用Flex逐步取代JSP,在取代JSP过程中可能存在Flex与JSP并存的情况,所以权限系统需要进行修改。
【SSH2权限系统的实现机制】
权限控制分为页面和后台两块:不同类型用户的帐号分配的访问权限是不同的,用户使用帐号登录系统以后,在页面中只能看到拥有权限的页面,并且如果用户通过浏览器直接输入链接地址,后台会判断该用户是否拥有该权限,如果没有则拒绝用户的请求。比如有个人信息管理和交易管理两个模块,管理员给用户A创建了一个帐号,并且给该帐号分配了可访问“个人信息管理”模块的权限,那么用户A登录系统后就只能看到“个人信息管理”的页面,“交易管理”页面是看不到的。那么用户可能知道访问“个人信息管理”的路径,可以在浏览器中输入请求地址,这时后台spring aop截获请求,然后判断该用户是否拥有该模块的访问权限,如果没有则抛出“没有权限”的错误消息,再通过拦截器控制直接返回到页面。
页面实现权限控制的方式比较简单:登录成功后将该用户拥有的所有权限放入session中,用户访问JSP页面时,从session中取得权限,然后在onload事件中遍历页面标签与session中的权限比对,判断标签是否有效,如果无效就不显示或者设为disable,如果有效则显示给用户。
后台实现权限控制使用了拦截器和AOP等机制:AOP过滤访问权限,无权限则抛出异常;拦截器捕获异常,最后返回相应错误消息到页面。
Spring AOP在用户访问Action某方法之前验证该用户是否拥有访问该方法的权限,如果可访问则放行,否则抛出无权限的自定义异常,随后Struts2拦截器会捕获异常,并且把“无访问权限”的错误消息发送的页面。
/** * about version :1.00 * Description :检查权限 * @throws Throwable */ public Object checkPriv(ProceedingJoinPoint pjp) throws Throwable{ //获取当前请求的用户信息和请求路径 user = ... accessUrl = ... //调用检查权限的方法,如果验证通过则允许继续执行,否则抛出无权限的异常 if (service.hasPriv(user, accessUrl)) { return pjp.proceed(); } else { throw new FunctionException(Constant4OSPMSException.NO_PRIVILEGE, "user has not privilege to do this!"); } } private PrivCtrlService service; /** * @return the service */ public PrivCtrlService getService() { return service; }
拦截器是Struts2框架的核心,从页面发送请求到后台以及从后台返回消息到页面都会经过拦截器,其功能类似于filter。在自带的拦截器内再包一层异常拦截器,如果项目发送异常,在自定义拦截器中捕获异常信息,并且根据异常id返回相应的异常消息。
关于Flex与Java整合都说烂了:HttpService、Web Service、RemoteObject。
HttpService等同于JSP中的Ajax请求,向服务器发送请求地址,然后通过Action返回响应数据,最后通过回调的形式获取Action的响应数据。这种形式可以延续使用Struts2,但是需要重新做一套针对Flex调用的Action(因为是Ajax,没法以return的形式重定向了)
Web Service除非跨语言、跨项目,通常不常用。
针对Flex权限对接有两种方案:
方案一:所有Flex请求均以Http形式访问Java服务,这样请求依然通过Struts2,原SSH2权限依然可用。使用此方案则当前项目MVC代码基本全部废弃,因为目前项目使用了大量表单提交、重定向,这些对Flex均不实用,全部都得改成Ajax形式通过PrintWriter输出数据给Flex。
public Object checkPriv(ProceedingJoinPoint pjp) throws Throwable{
//通过session获取权限的数据
FlexSession session = FlexContext.getFlexSession();
String privUrl = (String) session.getAttribute(Constant4Login.PRIVILEGE_SESSION);
if(privUrl==null){
System.out.println("Session失效...");
//抛出异常信息
throw new RuntimeException(…);
}
//获取切入的方法名
String methodName = getMethodName(pjp);
//获取切入的类全名
String className = getDeclaringClass(pjp);
//累全名和方法名拼接起来作为权限校验规则
methodName = className+"."+methodName;
//获取权限资源
String privs[] = privUrl.split("@");
for (String string : privs) {
//如果拥有权限则直接通过...
if(isEQuals(string, methodName)){
System.out.println("权限通过....");
return pjp.proceed();
}
}
System.out.println("权限未通过...");
//抛出无权限异常
throw new RuntimeException(…);
}
remote.addEventListener(FaultEvent.FAULT,error_); private function error_(event:FaultEvent):void{ Alert.show(event.toString()); }
方案二: [ 优 ] 运行效率快 [ 缺 ] 如何与 struts2 混用(即有的使用 jsp 、有的使用 flex )可能存在 jsp 请求后台时出现超过两次的权限校验的情况(两套 AOP ),业务层代码可能需要重构。