如何从使用选民的 AccessDecisionManager 抛出信息异常
Posted
技术标签:
【中文标题】如何从使用选民的 AccessDecisionManager 抛出信息异常【英文标题】:How to throw an informative exception from AccessDecisionManager that uses voters 【发布时间】:2010-10-05 09:08:42 【问题描述】:我有以下情况:我的应用程序的授权机制是使用Spring security实现的。中心类实现 AccessDecisionManager 并使用投票者(每个投票者都实现 AccessDecisionVoter)来决定是否授予对某些方法的访问权限。计票的算法是自定义的:
public class PermissionManagerImpl extends AbstractAccessDecisionManager
public void decide(
Authentication authentication,
Object object,
ConfigAttributeDefinition config) throws AccessDeniedException
Iterator<?> iter = getDecisionVoters().iterator();
boolean wasDenied = false;
while (iter.hasNext())
AccessDecisionVoter voter = (AccessDecisionVoter) iter.next();
int result = voter.vote(authentication, object, config);
switch (result)
// Some tallying calculations
if (wasDenied)
throw new AccessDeniedException("Access is denied");
在拒绝对某些方法的访问时,应用程序的客户端有兴趣获得一个信息异常,该异常详细说明为什么访问被拒绝。这意味着将一些信息从选民传递给决策经理。不幸的是,标准 AccessDecisionVoter 传递回决策管理器的唯一信息是可能的返回值之一(ACCESS_GRANTED、ACCESS_ABSTAIN 或 ACCESS_DENIED)。
最好的方法是什么?
谢谢。
【问题讨论】:
【参考方案1】:好吧,AccesssDecisionVoter
接口在这种情况下实际上返回了一个int
。诚然,内置的投票者实现总是只返回您提到的三个常量之一(这些是标准访问决策管理器检查的内容),但它们实际上并没有任何额外的返回 - RoleVoter
用于当且仅当主体没有所需的角色时,实例才会拒绝访问。
由于您使用自己的选民和访问决策管理器实现,因此我认为您有几个可用的选项:
-
以某种形式的错误代码返回其他整数值;将
ACCESS_GRANTED
、ACCESS_ABSTAIN
和ACCESS_DENIED
视为它们的典型值,但将任何其他整数视为带有错误代码的“拒绝访问”。理想情况下,有一个可用的错误代码查找表 - 本质上是一个穷人的枚举。
在你的投票者中,像往常一样返回ACCESS_DENIED
,并设置一些可公开访问的属性(在投票者对象本身或一些静态可访问的字段上)并说明错误原因。在您的经理中,如果您的自定义选民拒绝访问,请检查属性以获取详细信息。
如上,在voter中设置一个error属性;但请确保传入的Authentication
实例是您自己的自定义子类之一,它提供了良好的
设置/检索此信息的位置。
从你的选民内部抛出一个AccessDeniedException
(或合适的子类)。这并不理想,因为它预设了访问决策管理器中的逻辑;但是您可以直接让这个气泡上升,或者如果需要在管理器中捕获它(自定义子类肯定会对此有好处)并在访问确实被拒绝时重新抛出(类似于 ProviderManager
类对其 @ 所做的事情) 987654331@ 变量)。
这些都不是明显正确和优雅的答案,但是您应该能够从最合适的答案中得到可行的答案。由于在选民框架内没有明确支持沟通的原因(它基本上是一个直接的布尔响应)我认为你不能做得更好。
【讨论】:
【参考方案2】:你不能不使用选民直接实现AccessDecisionManager
吗?然后,您可以使用正确的信息发送AccessDeniedException
。也许RoleVoter
s 不是在您的情况下使用的正确抽象。
【讨论】:
【参考方案3】:感谢回答的人。
我想我找到了一种非常优雅的方式来做我想做的事,并且仍然使用标准的 voters API。 AccessDecisionVoter 的vote 方法的第二个参数是安全对象。我可以在决策经理和选民之间创建一个合同,该对象是一个特定的类/接口,它是一个包装器,通过它可以获取原始的安全对象,还可以获取其他信息由拒绝访问的选民添加。
我在其他框架中也看到了类似的模式。与其他可能的解决方案相比,此解决方案具有以下优势:
选民可以保持无国籍状态,因此他们可以是单身人士 使用了 AccessDecisionVoter 的标准接口,没有添加新的返回值 附加信息保存在一个自动丢弃的对象中,因为在 AbstactDecisionManager 的 decide 方法之后没有人使用它,因此不需要清理代码李>干杯。
【讨论】:
以上是关于如何从使用选民的 AccessDecisionManager 抛出信息异常的主要内容,如果未能解决你的问题,请参考以下文章
有没有办法从 Instagram 故事中检索民意调查选民名单?