发表时间:2009-03-02
最后修改:2009-03-02
上篇
中我们对
securityContextHolderAwareRequestFilter的丰富多彩有了个体验,
最后对这个类的名字也做了一个望文生义的解释. 本篇中我们将接着看上篇提到的子类,即SavedRequestAwareWrapper.
这个类在父亲的基业上又有什么新的突破呢? 这得从它的贤内助说起, 即这个子类的属性savedRequest
. 呵呵, 这也正是组合的好处.
我们看到SavedRequestAwareWrapper类里所有方法的实现都是基于这个贤内助的帮助. 拿我们熟悉的getCookies方法来说, 在执行这个方法时, 先要看贤内助的脸色: 如果
savedRequest没什么话说,才能执行父亲所传授的,即父类的方法
super.getCookies();
刚才看天下足球的"疯狂的足球", 而上面的内容也仅是我的想像,希望它较为贴切.
下面,我们看这个贤内助是怎么回事? Ta是何许人也呢? 读源码时发现, 这个
SavedRequest没什么背景, 没有继承, 只是实现了
Serializable接口. 那有什么用? 单独地看这个类是不行了, 不过发现这么一条语句:
SavedRequest
saved = (SavedRequest)
session.getAttribute(AbstractProcessingFilter.ACEGI_SAVED_REQUEST_KEY);
这里有一个get,那也应该有"人"set过, 难道说通往发现之路的入口?
经过一段时间的侦查, 终于发现那别有洞天! 在描述这个洞天前, 先看这么一个实际例子.
在CSDN网站里下载东西, 刚开始时我们先找, 找到一个一看评价不错, 那就下载吧,
可点下载按钮时,CSDN网站把我们引到登录页面, 噢, 原来还没登录呢. 很麻利地填写了登录信息后,点确定,
这时CSDN直接就把刚才要下载的东西拿出来了. 8错! 登录完后, 不必再从头找那个链接了. 可这是"8错"是怎么实现的呢?
我们用Acegi里的SavedRequest来描述下这个功能的实现,
当然CSDN不一定是用Acegi来实现的, 这里只是借用下那个情景. 在点"下载"按钮前, CSDN是允许我们浏览的,
也就是我们有匿名浏览的权限, 可当下载时, CSDN发现这个人没有下载的权限, 得让Ta登录. 于是,
CSDN里的安全机制让页面跳转到登录界面, 同时,为了用户的使用方便, 把用户刚才想下载的那个链接也记了下来, 放到了Session中,
而我们说的
SavedRequest正是干这个用的. 用户登录后, CSDN的安全机制再从Session中取出刚才那个想下载的链接, 于是下载顺利进行了.
下面结合前面介绍的Acegi概念,把这个过程再描述一遍. 刚才开始用户找东西时用浏览的权限, 当Ta想下载时, Acegi的
FilterSecurityInterceptor在执行
beforeInvocation方法时发现当前用户没有相应的权限, 于是
FilterSecurityInterceptor抛出一个
accessDeniedException异常, 这个异常在
ExceptionTranslationFilter里给catch住了, 随后的
handleException时, 由
sendStartAuthentication方法负责
new了一个SavedRequest
对象, 这个对象里正是装了刚才那个链接,随后把这个
SavedRequest对象放进了Session
. 于是用户登录, 登录妥当后,
AbstractProcessingFilter里的
successfulAuthentication方法出面通过
determineTargetUrl方法从session中取出前面放到session中的
SavedRequest对象, 最后再交由
sendRedirect方法, 把用户想要的东东呈现在了眼前.
说了半天了,
SavedRequest抢去了大多数的风头, 不过也好, 把这个
SavedRequest研究透了后,
SavedRequestAwareWrapper的功能就不攻自破了. 也就是说从历史地角度看清了SavedRequest对象的来龙去脉,
SavedRequestAwareWrapper对象的现在问题也就应刃而解了.