我们可能会有这样的需求,系统已经上线运行了。但是需要对某些人和某些方法进行权限过滤。
例如:我们允许张三进行所有操作,包括增删改查,只允许其他用户查询。
首先想到的可能是,在每个方法中都加入逻辑判断,这样违背了开闭原则,极有可能引入其它错误。
那么我们可以使用动态代理的方式,在运行时动态的进行权限校验,不需要修改原先的逻辑代码,
只要通过增加动态代理类、拦截器类、拦截器类。如下例:
启动类:
package com.bj.belen.demo;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.NoOp;
public class CGLIBTest {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Manager.class);
enhancer.setCallbacks(new Callback[]{
new AuthProxy("张三"), NoOp.INSTANCE});
enhancer.setCallbackFilter(new AuthProxyFilter());
Manager m = (Manager) enhancer.create();//生成代理对象
m.add();
}
}
权限过滤类:
package com.bj.belen.demo;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class AuthProxy implements MethodInterceptor {
private String userName;
public AuthProxy(String userName){
this.userName = userName;
}
public Object intercept(Object arg0, Method method, Object[] object,
MethodProxy proxy) throws Throwable {
System.out.println("begin auth");
if(!"张三".equals(this.userName)){
throw new RuntimeException("you don't have the authority");
}
System.out.println("you have the authority");
return proxy.invokeSuper(arg0, object);
}
}
拦截器类:
package com.bj.belen.demo;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.CallbackFilter;
public class AuthProxyFilter implements CallbackFilter{
public int accept(Method arg0) {
if(!"query".equalsIgnoreCase(arg0.getName()))
return 0;
return 1;
}
}
具体操作类:
package com.bj.belen.demo;
public class Manager {
public void query(){
System.out.println("begin query");
}
public void delete(){
System.out.println("begin delete");
}
public void update(){
System.out.println("begin update");
}
public void add(){
System.out.println("begin add");
}
}
在上述方法中,如果我们都去查询,那么将不会走权限过滤。否则如果是张三去添加,那么可以正常提交,会出现如下信息:
begin auth
you have the authority
begin add
否则会报出异常如下:
begin auth
Exception in thread "main" java.lang.RuntimeException: you don't have the authority
at com.bj.belen.demo.AuthProxy.intercept(AuthProxy.java:21)
at com.bj.belen.demo.Manager$$EnhancerByCGLIB$$4064f103.add(<generated>)
at com.bj.belen.demo.CGLIBTest.main(CGLIBTest.java:17)
其实现原理为:
在运行时动态生成代理类(该类继承了原有操作类),加入了权限拦截,并对某些方法不拦截。低层是使用ASM动态生成了一个新类字节码。