六年前,我开始从无到有写Lerx的时候,我看的是陈宝峰和张冰的教程。我就猜想是不是可以把权限的事与业务的事分开来搞?张冰的AOP教程中说可能可以实现,他把重点放在dobefore上,认为可以在执行之前检查后决定是否允许执行某个业务方法。当时我才接触SSH2框架,心高,但水平有限,摸索了几天都没搞起来。
这段时间有个业务在手上编写,因为Struts2框架漏洞频频,近期搞得我手忙脚乱。于是我决定抛弃Struts2奔向SpringMVC的怀抱。淘宝上4块钱买的SpringMVC 3和10块钱买的4的教程。看了一遍就开始下手,利用新的业务系统来练手。在练手的时候,我一边在整理自己的“框架”,目的就是大幅减少代码,缩短开发周期,提高效率。当我把后台业务差不多完成时,我考虚权限的事,AOP的经历浮现,然后我就开始再一次尝试了。网上找了一些材料,也有是用自定义注解,但是不是真正的AOP,有的是拦截器,有的是说不上来的东西。最终我如愿以偿。
最后就象盖公章一样,在需要权限检查的方法上盖个章(加个注释)就好了。猛然想起大话西游中的盘丝大仙,给至尊宝盖的那个章(三颗痣)。哈哈,盘丝大法。
好了,以上是背景,下面就直接把方法大致说一下。
1.建立一个自定义标签(上图的RoleCheck.java)
package com.krd.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.web.bind.annotation.ResponseBody;
//自定义注解相关设置
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RoleCheck {
/*
* role 用于标记权限的等级。比如:0的管理员,1是操作员,2是普通用户
* ajax 用于标记@ResponseBody注解的ajax返回。这类由于没有视图,可以返回一个字符串用于JavaScript判断和提示
*
*/
public int role() default -1;
public boolean ajax() default false;
}
2.编写AuthAspect,用于切入检查。我用的是环绕通知,并没有用前置通知。前权限检查成功时,通过return pjp.proceed();执行目标方法,否则返回无权限提示页forbid.jsp。
package com.krd.aop;
import javax.servlet.http.HttpSession;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.krd.annotation.RoleCheck;
import com.lerx.sys.util.StringUtil;
/*
* 试图通过aop实现权限控制功能,未能成功。以后再深入了解
* 6.7日晚补充:已成功!
*/
@Aspect
@Component
public class AuthAspect {
@Around(value="execution(* com.krd.handlers.*.*(..)) && @annotation(annotation)")
public Object around(ProceedingJoinPoint pjp,RoleCheck annotation) throws Throwable{
Boolean auth=false;
int role=annotation.role();
boolean ajax=annotation.ajax();
ServletRequestAttributes ra =(ServletRequestAttributes)RequestContextHolder.currentRequestAttributes();
HttpSession session=ra.getRequest().getSession();
if (session.getAttribute("mask")==null || !StringUtil.isNumber(""+session.getAttribute("mask"))){
return "forbid";
}
int mask=Integer.valueOf(""+session.getAttribute("mask"));
boolean adminLogin;
String adminLoginStr=""+session.getAttribute("admin_login_");
if (session.getAttribute("admin_login_")!=null && adminLoginStr.trim().equals("true")){
adminLogin=true;
}else{
adminLogin=false;
}
if (adminLogin){
switch (role){
case 0:
if (mask==0){ //当是0时,只有0--管理员有权限
auth=true;
}else{
auth=false;
}
break;
case 1:
if (mask>=0){ //当是1时,0--管理员和菜场管理员有权限
auth=true;
}else{
auth=false;
}
break;
default:
auth=false;
}
}else{
auth=false;
}
if (auth){
return pjp.proceed(); //这一行很重要!
}else{
if (ajax){
return "-1";
}else{
return "forbid";
}
}
}
/*@Before(value = "execution(* com.krd.handlers.*.*(..))")
public void doBefore(JoinPoint point) {
}
@Before(value = "execution(* com.krd.handlers.*.*(..))")
public void doAfter() {
} */
}
3.配置springmvc.xml
<!-- 上略 --> <!-- AOP --> <aop:aspectj-autoproxy proxy-target-class="true" /> <mvc:annotation-driven /> <bean id="aspect" class="com.krd.aop.AuthAspect"/> <!-- 下略 -->
4.下面就简单了。
在方法前加注解就可以了。如下图。
具体分析我懒得写了,有空再补充吧。