代码契约是否应用于安全?

6

有没有任何原因不使用代码合同来强制执行业务规则?

想象一下你有一个代表系统中单个用户并定义可以针对其他用户执行的操作的类。您可以编写像这样的ChangePassword方法...

public void ChangePassword(User requestingUser, string newPassword)
{
    Contract.Requires<ArgumentNullException>(requestingUser);
    Contract.Requires<ArgumentNullException>(newPassword);

    // Users can always change their own password, but they must be an
    // administrator to change someone else's.
    if (requestingUser.UserId != this.UserId &&
        !requestingUser.IsInRole("Administrator"))
        throw new SecurityException("You don't have permission to do that.");

    // Change the password.
    ...
}

或者你可以使用Contract.Requires将安全检查作为先决条件实现...

public void ChangePassword(User requestingUser, string newPassword)
{
    Contract.Requires<ArgumentNullException>(requestingUser != null);
    Contract.Requires<ArgumentNullException>(newPassword != null);

    // Users can always change their own password, but they must be an
    // administrator to change someone else's.
    Contract.Requires<SecurityException>(
        requestingUser.UserId == this.UserId ||
        !requestingUser.IsInRole("Administrator"),
        "You don't have permission to do that.");

    // Change the password.
    ...
}

这两种方法有哪些优缺点呢?
1个回答

2

我认为答案是否定的。Code Contracts是为代码中严重bug的情况而设计的,因此如果出现这种情况,就会失败。它们不应该是可以从错误的用户输入中恢复的东西。

Requires<T>只能在库的公共方法上使用,这些库将被其他未使用Code Contracts的人消费,或者您有需要以与其所能抛出异常相兼容的方式保持兼容的旧代码。

对于新代码,您应该只使用Requires,而不是Requires<T>。默认情况下,普通的Requires会抛出一个无法捕获的异常,以强制你解决问题。

此外,如果有人禁用了Code Contracts运行时检查,那么所有安全都将消失!


有人可能会认为,在某些情况下,你所举的例子确实是代码中的一个严重错误。例如,如果你正在编写的方法被深层嵌套,并且所有验证都应该在应用程序的外部层进行,则这可能被视为方法合同的一部分。这完全取决于情况 :) - porges
好的回答!我之前没有意识到ContractException是无法捕获的,但是你的回答指引了我正确的方向:http://www.infoq.com/articles/code-contracts-csharp - 谢谢! :) - Richard Poole

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接