我一直在努力解决这个问题。我想对ActionBean
和show
动作使用相同的Stripes update
。但是,我无法弄清楚如何以一种干净的方式来做到这一点,而这种方式不能允许当前用户对对象所有权进行可靠的绑定,验证和验证。
例如,假设我们的操作bean接受postingId
。该帖子属于已登录的用户。我们可能会有类似以下内容:
@UrlBinding("/posting/{postingId}")
@RolesAllowed({ "USER" })
public class PostingActionBean extends BaseActionBean
现在,对于
show
动作,我们可以定义: private int postingId; // assume the parameter in @UrlBinding above was renamed
private Posting posting;
现在使用
@After(stages = LifecycleStage.BindingAndValidation)
来获取Posting
。我们的@After
函数可以验证当前登录的用户是否拥有该帖子。我们必须使用@After
,而不是@Before
,因为postingId
不会事先绑定到该参数。但是,对于
update
函数,您想使用Posting
而不是@Before
将@After
对象绑定到Posting变量,以便将返回的表单条目应用到现有Posting对象的顶部,而不是到一个空的存根上。自定义
TypeConverter<T>
在这里可以很好地工作,但是由于无法从TypeConverter
界面进行会话,因此在绑定期间很难验证对象的所有权。我能看到的唯一解决方案是使用两个单独的动作bean,一个用于显示,另一个用于更新。但是,如果执行此操作,则
<stripes:form>
标记及其下游标记将无法正确填充表单的值,因为beanclass
或action
标记必须映射回相同的ActionBean
。据我所知,Stripes模型仅在处理简单(无POJO)参数时才组合在一起。在任何其他情况下,您似乎都陷入了困境:从数据存储中绑定对象并用客户端发送的更新覆盖对象。
我一定要错过一些东西。经验丰富的Stripes用户的最佳做法是什么?
最佳答案
在我看来,授权与对象水合作用正交。通过这种方式,我的意思是您应该将对象水化的关注点分开(在这种情况下,使用postingId
并将其转换为Posting
),而不要确定用户是否有权对该对象执行操作(例如show ,更新,删除等)。
对于对象水合,我使用TypeConverter<T>
,并且在不考虑会话用户的情况下为对象水合。然后在我的ActionBean
内部,我有一个守卫二传手的护卫,因此...
public void setPosting(Posting posting) {
if (accessible(posting)) this.posting = posting;
}
accessible(posting)
看起来像这样...private boolean accessible(Posting posting) {
return authorisationChecker.isAuthorised(whoAmI(), posting);
}
然后您的
show()
事件方法将如下所示:public Resolution show() {
if (posting == null) return NOT_FOUND;
return new ForwardResolution("/WEB-INF/jsp/posting.jsp");
}
另外,当我使用Stripes时,我经常在同一Stripes
ActionBean
中有多个事件(例如“ show”或“ update”)。对我而言,将相关名词的操作(动词)分组是有意义的。使用干净的URL,您的
ActionBean
批注将如下所示:@UrlBinding("/posting/{$event}/{posting}")
@RolesAllowed({ "USER" })
public class PostingActionBean extends BaseActionBean
...其中
{$event}
是事件方法的名称(即“显示”或“更新”)。请注意,我使用的是{posting}
,而不是{postingId}
。为了完整起见,这是您的
update()
事件方法可能看起来像的样子...public Resolution update() {
if (posting == null) throw new UnauthorisedAccessException();
postingService.saveOrUpdate(posting);
message("posting.save.confirmation");
return new RedirectResolution(PostingsAction.class);
}