集成测试用于检查应用程序的不同部分组装在一起时是否按预期工作。 使用集成测试时,您通常会希望跳过身份验证和授权测试。 例如,您可能对测试控制器方法更感兴趣,而不会妨碍身份验证和授权。
在本文中,我将讨论在ASP.Net Core中进行集成测试时如何绕过此类安全检查。
谁需要安全的集成测试?
您通常需要为上面带有[Authorize]标记的控制器方法编写集成测试。 假设您正在使用此属性命中一个身份提供程序(位于另一台服务器上)。 问题是,如果身份服务器关闭,则集成测试可能会失败。
因此,在控制器方法上运行集成测试时,绕过身份验证检查是一个好习惯。 毕竟,您只想测试应用程序管道,而不是外部服务器的可用性。 在以下各节中,我们将研究如何在集成测试中绕过[Authorize]属性。
在Visual Studio中创建一个ASP.Net Core Web API项目
首先,让我们创建一个ASP.Net Core项目。 如果您的系统已启动并运行Visual Studio 2017,请按照以下步骤在Visual Studio中创建一个新的ASP.Net Core项目。
- 启动Visual Studio 2017 IDE。
- 单击文件>新建>项目。
- 从显示的模板列表中选择“ ASP.Net Core Web应用程序(.Net Core)”。
- 指定项目的名称。
- 单击确定保存项目。
- 接下来显示一个新窗口“ New .Net Core Web Application…”。
- 选择.Net Core作为运行时,并从顶部的下拉列表中选择ASP.Net Core 2.2(或更高版本)。
- 选择API作为项目模板
- 确保未选中“启用Docker支持”和“配置HTTPS”复选框,因为我们此处将不再使用这些功能。
- 确保选择“无身份验证”,因为我们也不会使用身份验证。
- 单击确定。
这将在Visual Studio中创建一个新的ASP.Net Core Web API项目。
将身份验证添加到ASP.Net Core中的ConfigureServices方法
Startup.cs文件中的Startup类包含ConfigureServices方法。 请注意,ConfigureServices方法由运行时调用-您可以利用此方法将服务添加到管道。 接下来,在Startup.cs文件的ConfigureServices方法中编写以下代码。
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.Authority = "abcxyz.com";
options.Audience = "abcxyz.com";
});
}
在ASP.Net Core中创建控制器方法
现在创建一个名为DefaultController的控制器,其中包含以下代码。
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace BypassAuthentication.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class DefaultController : ControllerBase
{
[HttpGet]
public string Get()
{
return "Hello World!";
}
}
}
稍后,我们将利用此控制器编写集成测试。
在ASP.Net Core中创建测试项目
现在已经创建了ASP.Net Core Web API项目,让我们创建一个测试项目来编写集成测试。 为此,请按照以下步骤操作。
- 在Visual Studio IDE中,单击“文件”>“新建”>“项目”。
- 从已安装的模板列表中选择.Net Core。
- 从显示的模板列表中选择“ xUnit测试项目(.Net Core)”。
- 指定项目的名称。
- 单击确定保存。
将TestHost程序包添加到ASP.Net Core中的测试项目中
ASP.Net Core包含一个测试主机,您可以通过NuGet将其添加到集成测试项目中。 TestHost软件包为您提供了一个ASP.Net Core Web Server,您可以利用它编写和执行测试。
要安装TestHost软件包,请在“解决方案资源管理器”窗口中选择集成测试项目,右键单击,然后选择“管理NuGet软件包...”。 然后单击“浏览”,搜索“ Microsoft.AspNetCore.TestHost”软件包,然后安装该软件包。 您还应该从NuGet安装Microsoft.AspNetCore.Diagnostics和Microsoft.AspNetCore.Mvc程序包(请参见下面的屏幕图像)。
在ASP.Net Core测试项目中创建集成测试
在上述步骤中在ASP.Net Core中创建测试项目时,将在项目中自动创建测试类。 用以下代码替换默认创建的测试类。
public class MyTests
{
private readonly TestServer testServer;
private readonly HttpClient httpClient;
public MyTests()
{
testServer = new TestServer(new WebHostBuilder()
.UseStartup<Startup>());
httpClient = testServer.CreateClient();
}
[Fact]
public async Task GetMessageTestAsync()
{
var response = await httpClient.GetAsync("http://localhost:13022/api/default");
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadAsStringAsync();
Assert.NotNull(result);
}
}
请注意TestServer的用法以及如何在构造函数中配置httpClient实例。 只要控制器或控制器方法上没有[Authorize]属性,GetMessageTestAsync测试方法就可以正常运行。
但是,如果控制器或控制器方法具有[Authorize]标记,则GetMessageTestAsync测试方法将失败,说明您无权调用控制器的Get方法。 现在让我们检查一下在运行集成测试时如何绕过此安全检查。
绕过ASP.Net Core中的身份验证/授权检查
要绕过身份验证/授权检查,我们需要创建一个虚拟的Startup类。 为此,我们应该创建一个扩展Startup类并覆盖其方法的类。 首先,我们应该重新组织ConfigureServices方法,以便以后可以覆盖它。 这是ConfigureServices方法的更新版本。
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
ConfigureAuthentication(services);
}
protected virtual void ConfigureAuthentication(IServiceCollection services)
{
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.Authority = "abcxyz.com";
options.Audience = "abcxyz.com";
});
}
在ASP.Net Core测试项目中创建虚拟启动类
在测试项目中,创建一个虚拟的Startup类,如下面的代码片段所示。
public class FakeStartup : Startup
{
public FakeStartup(IConfiguration configuration) : base(configuration)
{
}
protected override void ConfigureAuthentication(IServiceCollection services)
{
//Write your implementation of fake authentication here
}
}
接下来,您应该使用以下代码更新MyTests类(这是我们的测试类)的构造函数。 请注意,TestServer现在使用FakeStartup类。
public MyTests()
{
testServer = new TestServer(new WebHostBuilder()
.UseStartup<FakeStartup>());
httpClient = testServer.CreateClient();
}
创建自定义身份验证处理程序类以伪造身份验证
请注意,如果您现在运行测试,测试仍将失败,因为未在FakeStartup类中指定身份验证中间件。 为此,您应该创建一个自定义身份验证处理程序类,该类扩展AuthenticationHandler类并覆盖HandleAuthenticateAsync方法。 您可以通过这种方法批准或拒绝身份验证请求。
最后,您应该在我们之前创建的FakeStartup类中指定自定义身份验证中间件。 我将把这部分留给您自己实现。
这就是您需要做的! 您的集成测试现在可以完美运行,因为将绕过安全检查。
集成测试通常需要利用基础结构方面的优势-数据库资源,文件系统资源,Web请求和响应等。因此,您将不希望集成测试检查身份验证/授权,尤其是如果您的安全框架驻留在外部服务器。 通过创建虚拟的Startup类和虚拟的身份验证中间件,您可以完成工作。