我正在尝试使用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的方法来进行单元测试。