集成测试时如何绕过自定义属性?
How do I bypass a Custom Attribute when Integration Testing?
基本上,我想使用 net6.0 进行干净的集成测试。我想调用我的控制器的端点,它最终会进入数据库并写入一些数据。之后,我将断言插入数据的某些方面。
我可以绕过 [Authorize]
属性使用的 Bearer Token 但无法绕过名为 [HasPermission]
的自定义属性
我有这个自定义属性:
public class HasPermission : TypeFilterAttribute
{
public HasPermission(string resource, string scope)
: base(typeof(HasPermissionAuthorize))
{
Arguments = new object[] { resource, scope };
}
};
public class HasPermissionAuthorize : IAuthorizationFilter
{
private readonly string _resource;
private readonly string _scope;
private readonly IAuthService _authService;
public HasPermissionAuthorize(string resource, string scope, IAuthService authService)
{
_resource = resource;
_scope = scope;
_authService = authService;
}
public async void OnAuthorization(AuthorizationFilterContext context)
{
string token = context.HttpContext.Request.Headers["Authorization"];
token = token.Replace("Bearer ", "");
bool hasPermission = await _authService.HasClaimAsync(token, "permission", _resource + "." + _scope);
if (!hasPermission)
{
context.Result = new UnauthorizedResult();
}
}
这是我的控制器:
[Authorize] //<-- I can bypass this
[Route("v1/[controller]")]
[ApiController]
public class MachinesController : ControllerBase
{
[HasPermission("Machines", "Create")] //<-- How do I bypass this?
[HttpPost]
public async Task<IActionResult> Post([FromBody] AddMachineRequest request)
{
//some logic
}
}
在我的集成测试中
public class ApiWebApplicationFactory : WebApplicationFactory<Startup>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
//I'm bypassing the [Authorize] attribute here
//However, I do not know how to bypass [HasPermission] attribute
services.AddMvc(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.AddAuthenticationSchemes("Test")
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = "Test";
options.DefaultChallengeScheme = "Test";
options.DefaultScheme = "Test";
}) //TestAuthHandler is written somewhere else
.AddScheme<AuthenticationSchemeOptions, TestAuthHandler>("Test", options => { });
}
}
}
我正在使用 IClassFixture<ApiWebApplicationFactory>
测试我的代码。尽管我可以绕过 [Authorize]
属性,但我找不到绕过 [HasPermission]
属性的优雅方法。
好的。我已经在考虑 Mocking IAuthService
但正如 Guru Stron 指出的那样,我选择了这种方法。所以,这是我对解决我的问题的代码的最新更新:
public class ApiWebApplicationFactory : WebApplicationFactory<Startup>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
//Added this line
services.AddTransient<IAuthService>(_ => _authServiceMock.Object);
//Above somewhere I also mocked it like this:
//_authServiceMock.Setup(c => c.HasClaimAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).ReturnsAsync(true);
//other stuff from my original question remains here and they are the same
}
}
}
基本上,我想使用 net6.0 进行干净的集成测试。我想调用我的控制器的端点,它最终会进入数据库并写入一些数据。之后,我将断言插入数据的某些方面。
我可以绕过 [Authorize]
属性使用的 Bearer Token 但无法绕过名为 [HasPermission]
我有这个自定义属性:
public class HasPermission : TypeFilterAttribute
{
public HasPermission(string resource, string scope)
: base(typeof(HasPermissionAuthorize))
{
Arguments = new object[] { resource, scope };
}
};
public class HasPermissionAuthorize : IAuthorizationFilter
{
private readonly string _resource;
private readonly string _scope;
private readonly IAuthService _authService;
public HasPermissionAuthorize(string resource, string scope, IAuthService authService)
{
_resource = resource;
_scope = scope;
_authService = authService;
}
public async void OnAuthorization(AuthorizationFilterContext context)
{
string token = context.HttpContext.Request.Headers["Authorization"];
token = token.Replace("Bearer ", "");
bool hasPermission = await _authService.HasClaimAsync(token, "permission", _resource + "." + _scope);
if (!hasPermission)
{
context.Result = new UnauthorizedResult();
}
}
这是我的控制器:
[Authorize] //<-- I can bypass this
[Route("v1/[controller]")]
[ApiController]
public class MachinesController : ControllerBase
{
[HasPermission("Machines", "Create")] //<-- How do I bypass this?
[HttpPost]
public async Task<IActionResult> Post([FromBody] AddMachineRequest request)
{
//some logic
}
}
在我的集成测试中
public class ApiWebApplicationFactory : WebApplicationFactory<Startup>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
//I'm bypassing the [Authorize] attribute here
//However, I do not know how to bypass [HasPermission] attribute
services.AddMvc(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.AddAuthenticationSchemes("Test")
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = "Test";
options.DefaultChallengeScheme = "Test";
options.DefaultScheme = "Test";
}) //TestAuthHandler is written somewhere else
.AddScheme<AuthenticationSchemeOptions, TestAuthHandler>("Test", options => { });
}
}
}
我正在使用 IClassFixture<ApiWebApplicationFactory>
测试我的代码。尽管我可以绕过 [Authorize]
属性,但我找不到绕过 [HasPermission]
属性的优雅方法。
好的。我已经在考虑 Mocking IAuthService
但正如 Guru Stron 指出的那样,我选择了这种方法。所以,这是我对解决我的问题的代码的最新更新:
public class ApiWebApplicationFactory : WebApplicationFactory<Startup>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
//Added this line
services.AddTransient<IAuthService>(_ => _authServiceMock.Object);
//Above somewhere I also mocked it like this:
//_authServiceMock.Setup(c => c.HasClaimAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).ReturnsAsync(true);
//other stuff from my original question remains here and they are the same
}
}
}