我正在尝试使用 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/其他方式触发处理程序,则不会引发异常,并且一切正常。
Thread.CurrentPrincipal = handler.ValidateToken(token, validationParameters, out securityToken);
HttpContext.Current.User = handler.ValidateToken(token, validationParameters, out securityToken);
我不明白当第一行几乎相同的行工作时,是什么导致仅第二行出错 - 两行都调用相同的方法。我不明白为什么它可以与第三方软件一起使用,但不能与我的测试代码一起使用 - 我担心的是,如果我没有弄清楚这一点以进行单元测试,那么我将无法使代码适用于真实应用程序调用此 api。我认为这是我的测试代码中的一些琐碎设置,我需要在提交之前将其添加到我的请求中。但也许我需要在单元测试中构建一种完全不同的调用 API 的方法。
我不会这样做。
在这种情况下我所做的是编写涵盖令牌逻辑的集成测试。
这意味着调用令牌端点,检索令牌,然后调用其他内容并看看会发生什么。
然后,您可以添加其他测试,例如令牌丢失、无效、已过期或包含错误声明时会发生什么情况。