我们可能会有这样的需求,系统已经上线运行了。但是需要对某些人和某些方法进行权限过滤。
例如:我们允许张三进行所有操作,包括增删改查,只允许其他用户查询。
首先想到的可能是,在每个方法中都加入逻辑判断,这样违背了开闭原则,极有可能引入其它错误。
那么我们可以使用动态代理的方式,在运行时动态的进行权限校验,不需要修改原先的逻辑代码,
只要通过增加动态代理类、拦截器类、拦截器类。如下例:
启动类:
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动态生成了一个新类字节码。