You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Framework 4.8 WebAPI控制器集成测试忽略JwtAuthentication属性问题

问题原因及解决方案

直接调用控制器方法时,Web API的请求处理管道并未启动,标记在方法上的IAuthenticationFilter不会被自动触发。这类过滤器是Web API框架在处理HTTP请求的流程中负责调用的,手动调用方法绕开了整个管道,因此认证逻辑完全被跳过。

解决方案一:手动触发认证过滤器

手动实例化JwtAuthenticationAttribute并调用其AuthenticateAsync方法,传入控制器上下文来执行认证逻辑。同时需要补全过滤器中的异常抛出逻辑,确保测试能捕获到预期异常。

补全过滤器的认证逻辑

public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
    var request = context.Request;
    var authorization = request.Headers.Authorization;

    if (authorization == null || authorization.Scheme != "Bearer" || string.IsNullOrEmpty(authorization.Parameter))
    {
        throw new JwtAuthenticationException("无效或缺失JWT令牌");
    }

    var token = authorization.Parameter;
    // 后续令牌验证逻辑...
}

修改测试方法

[TestMethod]
[ExpectedException(typeof(JwtAuthenticationException))]
public async Task GetISOCodes_NoHeader_ThrowException()
{
    // Arrange
    var authAttribute = new JwtAuthenticationAttribute();
    var controllerContext = new HttpControllerContext 
    { 
        RequestContext = new HttpRequestContext(),
        Request = new HttpRequestMessage()
    };
    languagecontroller.ControllerContext = controllerContext;

    var authContext = new HttpAuthenticationContext(controllerContext, null);

    // 手动执行认证逻辑
    await authAttribute.AuthenticateAsync(authContext, CancellationToken.None);

    // 若认证失败,此处已抛出异常
    await languagecontroller.GetISOCodes();
}

[TestMethod]
[ExpectedException(typeof(JwtAuthenticationException))]
public async Task GetISOCodes_WithHeader_ThrowException()
{
    // Arrange
    var token = string.Empty;
    var authAttribute = new JwtAuthenticationAttribute();
    var controllerContext = new HttpControllerContext 
    { 
        RequestContext = new HttpRequestContext(),
        Request = new HttpRequestMessage()
    };
    controllerContext.Request.Headers.Add("Authorization", "Bearer " + token);
    languagecontroller.ControllerContext = controllerContext;

    var authContext = new HttpAuthenticationContext(controllerContext, null);

    // 手动执行认证逻辑
    await authAttribute.AuthenticateAsync(authContext, CancellationToken.None);

    // 若认证失败,此处已抛出异常
    await languagecontroller.GetISOCodes();
}

解决方案二:使用Web API测试服务器(推荐)

通过HttpServer和HttpClient模拟真实HTTP请求,让Web API完整的请求管道运行,过滤器会自动触发,测试场景更贴近真实环境。

测试代码示例

[TestMethod]
public async Task GetISOCodes_NoHeader_ReturnsUnauthorized()
{
    // 配置Web API
    var config = new HttpConfiguration();
    config.MapHttpAttributeRoutes();
    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{action}",
        defaults: new { action = RouteParameter.Optional }
    );

    using (var server = new HttpServer(config))
    using (var client = new HttpClient(server))
    {
        // Act
        var response = await client.GetAsync("api/Language/GetISOCodes");

        // Assert
        Assert.AreEqual(HttpStatusCode.Unauthorized, response.StatusCode);
        
        // 若过滤器抛出异常,可读取错误信息
        var error = await response.Content.ReadAsAsync<HttpError>();
        Assert.AreEqual("无效或缺失JWT令牌", error.Message);
    }
}

[TestMethod]
public async Task GetISOCodes_EmptyToken_ReturnsUnauthorized()
{
    var config = new HttpConfiguration();
    config.MapHttpAttributeRoutes();
    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{action}",
        defaults: new { action = RouteParameter.Optional }
    );

    using (var server = new HttpServer(config))
    using (var client = new HttpClient(server))
    {
        // Arrange
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", string.Empty);

        // Act
        var response = await client.GetAsync("api/Language/GetISOCodes");

        // Assert
        Assert.AreEqual(HttpStatusCode.Unauthorized, response.StatusCode);
        var error = await response.Content.ReadAsAsync<HttpError>();
        Assert.AreEqual("无效或缺失JWT令牌", error.Message);
    }
}

注意事项

如果过滤器中使用context.ErrorResult而非直接抛出异常,测试时应验证响应的状态码和错误内容,而非依赖ExpectedException特性。

内容的提问来源于stack exchange,提问作者Drahcir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 22:50:33