使用 Web API 对 JWT 令牌进行单元测试

Posted

技术标签:

【中文标题】使用 Web API 对 JWT 令牌进行单元测试【英文标题】:Unit Testing a JWT Token with Web API 【发布时间】:2018-12-23 11:56:47 【问题描述】:

我正在尝试使用 Web API2、JWT、Microsoft.IdentityModel.JsonWebTokens 5.2.422 和本文所述的令牌验证逻辑:http://www.decatechlabs.com/secure-webapi-using-jwt

当我重复本文中的步骤(包括通过 Restlet 测试 API)时,一切对我的项目都很有效。但是,我正在尝试对这个项目使用测试驱动开发 (TDD),理想情况下,我想测试我的测试中的一切是否正常,包括令牌验证处理程序。如果我在单元测试中直接调用它们,我可以测试我的控制器,但这绕过了实际的令牌验证处理程序。因此,我尝试使用自托管 HTTP 来正确执行完整的 API,包括所有令牌验证处理程序逻辑。这是我获取令牌然后将令牌传递给需要授权的第二种方法的完整单元测试:

[TestMethod]

public void GetAuthorizedStatus_SelfHostedHTTP()

    HttpServer server = TestAPIHelper.GenerateTestServer();

    using (HttpMessageInvoker client = new HttpMessageInvoker(server))
    
        string token = string.Empty;

        using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, loginURL))
        
            var stringContent = new StringContent(JsonConvert.SerializeObject(TestAPIHelper.loginObject), Encoding.UTF8, "application/json");
            request.Content = stringContent;

            using (HttpResponseMessage response = client.SendAsync(request, System.Threading.CancellationToken.None).Result)
            
                Assert.AreEqual(HttpStatusCode.OK, response.StatusCode, "Error getting token from login portion");

                token = response.Content.ReadAsAsync<string>().Result;
                Assert.IsTrue(token.Length > 50);
            
        

        using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, authorizedStatusURL))
        
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);

            using (HttpResponseMessage response = client.SendAsync(request, System.Threading.CancellationToken.None).Result)
            
                Assert.AreEqual(HttpStatusCode.OK, response.StatusCode, "Error getting status from Authenticated portion.");
            
        
    ;

问题在于 TokenValidationHandler 抛出“对象引用未设置为对象的实例”。处理程序下面两行中的第二行的异常,仅当我的单元测试调用并附加了令牌时。如果我使用 Restlet/Postman/whatever 触发处理程序,则不会引发异常并且一切正常。

Thread.CurrentPrincipal = handler.ValidateToken(token, validationParameters, out securityToken);
HttpContext.Current.User = handler.ValidateToken(token, validationParameters, out securityToken);

当第一行几乎相同的行工作时,我不明白是什么导致第二行出错 - 两行都调用相同的方法。而且我不明白为什么它可以与第三方软件一起使用,但不能与我的测试代码一起使用——我担心的是,如果我不为单元测试解决这个问题,那么我将无法让代码为调用此 api 的真实应用程序。我认为这是我的测试代码中的一些琐碎设置,我需要在提交之前添加到我的请求中。但也许我需要在我的单元测试中构建一种完全不同的调用 API 的方法。

【问题讨论】:

【参考方案1】:

我不会这样做的。

我在这种情况下所做的是编写涵盖令牌逻辑的集成测试。

这意味着调用令牌端点,检索令牌,然后调用其他东西并查看会发生什么。

然后您可以添加其他测试,例如令牌丢失、无效、过期或包含错误声明时会发生什么。

【讨论】:

以上是关于使用 Web API 对 JWT 令牌进行单元测试的主要内容,如果未能解决你的问题,请参考以下文章

如何跨不同 API 对 JSON Web 令牌 (JWT) 进行身份验证?

单元测试 JWT 令牌过期:Django REST

如何测试使用 JWT 身份验证的节点 API(使用用户登录获取令牌)

.NET Core 2 Web API JWT 令牌无法识别

Json Web 令牌 JWT

Web Api JWT 令牌认证