单元测试自定义的Web API授权属性

9

我正在尝试使用C#中的NUnit对自定义授权属性进行单元测试。特别是在未被授权的情况下,返回了特定的HTTP状态码和消息。

我的属性非常简单-代码如下:

public class AuthorizationAttribute : AuthorizeAttribute
{

    public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        if (IsAuthorized(actionContext))
            return;

        HandleUnauthorizedRequest(actionContext);
    }

    protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.Forbidden, "You are not authorized to access this resource");
    }
}

所以为了测试这个(目前测试领域内较新的东西),我拼凑了以下代码。其中,我附加了一个通用的身份,包括用户名和一些角色数据。

public void Given_UserIsNotInAuthorizedRoles_When_Auhtorizing_ReturnsForbidden()
{

    // Arrange

    IPrincipal principal = new GenericPrincipal(new GenericIdentity("TestName"), new[] { "TestRole" });

    HttpActionContext mockActionContext = new HttpActionContext()
    {
        ControllerContext = new HttpControllerContext()
        {
            Request = new HttpRequestMessage(),
            RequestContext = new HttpRequestContext() { Principal = principal }
        },
        ActionArguments = { { "SomeArgument", "null" } }
    };

    mockActionContext.ControllerContext.Configuration = new HttpConfiguration();
    mockActionContext.ControllerContext.Configuration.Formatters.Add(new JsonMediaTypeFormatter());

    // Act
    AuthorizationAttribute authAttr = new AuthorizationAttribute();
    authAttr.OnAuthorization(mockActionContext);

    // Assert
    Assert.IsTrue(mockActionContext.Response.StatusCode == System.Net.HttpStatusCode.Forbidden);

}

模拟控制器长这样:
[Authorization(Roles = "AdminRoleOnly", Users = "A user")]
internal class MockController : ApiController { }

当我在调试时,发现if(IsAuthorized(actionContext))返回了true,这一点令我难以理解。
请问有人能指导我为什么我的授权属性会将此标识符视为有效吗?
值得一提的是,该代码在生产环境中可用。我正在补充一些测试。
与此有关的内容如下:
我已经阅读了一个类似问题的问题和答案ASP.NET MVC unit testing custom AuthorizeAttribute,尽管两者都不能正常工作或相关,特别是因为它们是针对MVC控制器而不是Api Controllers的。
我还阅读并尝试实现了这个问题的答案中的代码Mocking HttpActionContext.ActionArguments when testing Web.Api ActionFilter
后一个方法使我接近成功,因为我的授权属性正在测试中触发,我可以传递所需的上下文信息。

你期望的是哪种行为?如果(IsAuthorized(actionContext))返回true,那么它意味着你提供的mockActionContext是有效的 :) 你知道IsAuthorized函数中发生了什么吗? - Ouarzy
我期望IsAuthorized返回false。我的原则与模拟控制器AuthorizeAttribute具有不同的角色。我的原则是Authenticated,尽管不同。我正在调用的IsAuthorized方法位于AuthorizeAttribute的基础上。MSDN说它只是指示特定控件是否经过授权。这是基于角色等情况发生的理解。 - Darren Wainwright
看一下IsAuthorized的源代码中正在发生什么。 - Nkosi
@Nkosi - 谢谢。那么,如果我完全删除原则,为什么它不返回false?它应该在第一个“if”上返回false。 - Darren Wainwright
嗨,我想问一下:在这行代码 authAttr.OnAuthorization(mockActionContext); 中,我遇到了错误 "Object reference not set to an instance of an object",不确定我做错了什么? - zeroflaw
1
@zeroflaw 你可能已经解决了,但是对于那些遇到相同问题的人-请确保上下文中的响应对象不为null :) - Iris Classon
1个回答

3
您需要将AuthorizationAttribute分配一个Role。在您的示例中,您将分配给了主体。请分配任何其他角色,但不要分配该角色。
// Act
AuthorizationAttribute authAttr = new AuthorizationAttribute() {
    Roles = "SomeOtherRole"
};

当进行测试时,测试应该按预期行为运作。

如果您查看 IAuthorized 的源代码,您将看到逻辑检查属性是否分配了角色。如果没有要比较的角色,则默认为true


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