java在AspectJ中禁用/避免执行通知
假设我有一个方面
public aspect Hack {
pointcut authHack(String user, String pass): call(* Authenticator.authenticate(String,String)) && args(user,pass);
boolean around(String user, String pass): authHack(user,pass) {
out("$$$ " + user + ":" + pass + " $$$");
return false;
}
}
{
是否可以编写第二个方面来取消/禁用Hack方面的authHack
建议
我可以捕获around authHack
建议的执行,但是如果我想继续验证,我需要再次调用Authenticator.authenticate
,这会创建一个无限循环
# 1 楼答案
实际上,user@Yaneeve提供了一个很好的解决方案,但它有一些缺点,例如
call()
,不适用于execution()
declare precedence
*
可以避免这种情况)李>我有一个更稳定的解决方案。我对源代码进行了修改,使其更加真实:
验证者:
验证器有一个用户数据库(为简单起见,硬编码),并实际比较用户和密码
应用程序:
应用程序有一个入口点,并尝试验证几个用户,打印结果:
应用程序的输出如下所示:
身份验证记录器方面:
我想添加一个关于身份验证方法的
around()
建议的法律方面,就像后面的黑客方面一样输出变成:
如你所见,“状态”和“认证结果”是相同的,只要系统没有被黑客攻击。这并不奇怪
黑客方面:
现在让我们破解这个系统。我们可以总是返回true(肯定的身份验证结果),也可以总是为某个用户返回true——不管我们喜欢什么。如果我们想得到它的副作用,我们甚至可以
proceed()
到原始调用,但我们仍然可以始终返回true,这就是我们在本例中所做的:输出更改为:
因为黑客方面声明自己是通知优先级中的最后一个(即嵌套的
proceed()
序列中最内层的shell)在同一连接点上调用时,其返回值将沿着调用链向上传播到记录器方面,这就是记录器在从内部方面接收到已处理的身份验证结果后打印该结果的原因如果我们将声明更改为
declare precedence : Hack, *;
,则输出如下:也就是说,记录器现在会记录原始结果,并将其沿调用链向上传播到黑客方面,黑客方面可以在最后对其进行操作,因为它优先,因此可以控制整个调用链。拥有最终发言权是黑客通常想要的,但在这种情况下,它会显示所记录的内容(一些验证为真,一些为假)与应用程序实际行为之间的不匹配(因为被黑客攻击,所以始终为真)
反黑客方面:
现在,最后但并非最不重要的一点是,我们想要截获建议执行,并确定它们是否可能来自可能的黑客方面。好消息是:AspectJ有一个切入点叫做
adviceexecution()
-nomen est omen.:-)通知执行连接点具有可通过
thisJoinPoint.getArgs()
确定的参数。不幸的是,AspectJ无法通过args()
将它们绑定到参数。如果截获的通知是around()
类型,则第一个adviceexecution()
参数将是AroundClosure
对象。如果对这个闭包对象调用run()
方法并指定正确的参数(可以通过getState()
确定),其效果是不会执行实际的通知体,而只会隐式地调用proceed()
。这将有效地禁用截获的建议结果是:
如你所见
catchHack()
切入点中,我们指定了一个已知方面的白名单,该白名单不应被禁用,即运行不变around()
建议,因为before()
和after()
建议有没有AroundClosure
的签名使用目标冰毒的反黑客建议od启发法:
不幸的是,我发现没有办法确定around闭包所针对的方法,因此没有确切的方法将反黑客建议的范围限制为专门针对我们想要防止黑客攻击的方法的建议。在本例中,我们可以通过试探性地检查
AroundClosure.getState()
返回的数组的内容来缩小范围,该数组包含Authenticator
实例)Authenticator.authenticate()
,必须有两个String
)李>我通过反复试验发现,这些知识是没有记录的(就像advice execution的论点内容一样)。无论如何,此修改启用了启发式:
输出与上面一样,但是如果黑客方面或者甚至多个黑客方面有多个建议,你就会看到不同。这个版本正在缩小范围。你是否想要这个取决于你自己。我建议你使用更简单的版本。在这种情况下,您只需要小心地更新切入点,以始终拥有最新的白名单
很抱歉回答得太长,但我发现这个问题很有趣,并尽可能好地解释了我的解决方案
# 2 楼答案
我想你错过了电话。你可能想要的是这样的:
# 3 楼答案
为了模拟您的情况,我编写了以下验证器代码:
这是我的主要课程:
输出为:
我添加了你的黑客方面:
现在输出是:
现在来看看解决方案:
我创建了以下HackTheHack特性:
输出再次是:
只有当黑客方面最初的切入点是“调用”而不是“执行”时,这才有效,因为执行实际上捕捉到了反射
说明:
我使用方面优先级在Hack之前调用Hack thehack:
然后,我使用反射(注意,可以而且应该进行优化,以减少对方法的重复查找)来简单地调用原始方法,而不需要Hack-around建议。这之所以成为可能,是因为两件事:
pointcut authHack(String user, String pass): call(* Authenticator.authenticate(String,String)) && args(user,pass);
使用call()
而不是execution()
proceed()
我想向你们介绍一下Manning's AspectJ in Action, Second Edition,它使我在以下方面走上了正确的道路: