如何使用[授权]属性集成测试ASP 5/Core Web API



我目前有一个ASP 5/ASP Core Web API,需要与OWIN测试服务器进行集成测试。

问题是,我在生产中使用IdentityServer作为授权服务器,并且我不想将授权作为集成测试的一部分。

这是API的Startup.cs:

public Startup(IHostingEnvironment env)
{
    // Set up configuration sources.
    IConfigurationBuilder builder = new ConfigurationBuilder()
        .AddJsonFile("appsettings.json")
        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", true);
    if (env.IsEnvironment("Development"))
    {
        // This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.
        builder.AddApplicationInsightsSettings(developerMode: true);
    }
    builder.AddEnvironmentVariables();
    Configuration = builder.Build().ReloadOnChanged("appsettings.json");
}
public IConfigurationRoot Configuration { get; set; }
// This method gets called by the runtime. Use this method to add services to the container
public IServiceProvider ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddApplicationInsightsTelemetry(Configuration);
    ConfigureEntityFrameworkDatabase(services, Configuration);
    services.AddIdentity<IdentityUser, IdentityRole>()
        .AddEntityFrameworkStores<HoehenSuchtIdentityDbContext>()
        .AddDefaultTokenProviders();
    ConfigureMvc(services);
    // register autofac as dependency resolver
    ContainerBuilder containerBuilder = new ContainerBuilder();
    // register all required autofac modules
    RegisterAutofacModules(containerBuilder);
    // register all automapper mappings as di services so there dependencies can be resolved
    ConfigureAutomapper(containerBuilder);
    ConfigureSwagger(services);
    // copy all asp core dependency injection registrations to autofac
    containerBuilder.Populate(services);
    IContainer container = containerBuilder.Build();
    return container.Resolve<IServiceProvider>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();
    if (env.IsDevelopment())
    {
        app.UseBrowserLink();
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    // make sure the database was created and all migrations applied
    MigrateDatabase(app);
    app.ApplicationServices.GetService<HoehenSuchtDbContext>().EnsureSeedData(env);
    app.UseIISPlatformHandler();
    app.UseApplicationInsightsRequestTelemetry();
    app.UseApplicationInsightsExceptionTelemetry();
    ConfigureIdentityServer(app, Configuration);
    app.UseStaticFiles();
    app.UseMvc();
    //app.UseSwaggerGen(/*routeTemplate: "docs/{apiVersion}/swagger.json"*/);
    //app.UseSwaggerUi(/*baseRoute: "docs", swaggerUrl: "docs/v1/swagger.json"*/);
}
public static Action<IServiceCollection, IConfigurationRoot> ConfigureEntityFrameworkDatabase = (services, config) =>
{
    services.AddEntityFramework()
        .AddSqlServer()
        .AddDbContext<HoehenSuchtDbContext>(builder =>
            builder.UseSqlServer(config["Data:DefaultConnection:ConnectionString"]))
        .AddDbContext<HoehenSuchtIdentityDbContext>(builder =>
            builder.UseSqlServer(config["Data:IdentityConnection:ConnectionString"]));
};
public static Action<IServiceCollection> ConfigureMvc = services =>
{
    services.AddMvc().AddControllersAsServices(new List<Assembly> { typeof(Startup).GetTypeInfo().Assembly });
};

我已经尝试注册了一个特殊的测试中间件,理论上它应该进行身份验证并设置声明主体。但在OWIN管道的某个地方,身份验证被拒绝,我得到了401错误代码。

这就是我如何设置OWIN测试服务器:

Startup.MigrateDatabase = app =>
{
    app.ApplicationServices.GetService<HoehenSuchtDbContext>().Database.EnsureCreated();
};
Startup.ConfigureEntityFrameworkDatabase = ApiTestServer.ConfigureInMemoryDatabase;
Startup.ConfigureIdentityServer = (app, config) =>
{
    app.ApplicationServices.GetService<HoehenSuchtDbContext>().EnsureSeedData(new HostingEnvironment {EnvironmentName = "development" });
    app.UseMiddleware<AuthenticatedTestRequestMiddleware>();
};
Server = new TestServer(TestServer.CreateBuilder().UseStartup<Startup>());

这是我的自定义AuthenticatedTestRequestMiddleware:

public class AuthenticatedTestRequestMiddleware
{
    public const string TestingCookieAuthentication = "TestCookieAuthentication";
    public const string TestingHeader = "X-Integration-Testing";
    public const string TestingHeaderValue = "78EAAA45-E68B-43C7-9D12-3A5F1E646BD5";
    private readonly RequestDelegate _next;
    public AuthenticatedTestRequestMiddleware(RequestDelegate next)
    {
        _next = next;
    }
    public async Task Invoke(HttpContext context)
    {
        if (context.Request.Headers.Keys.Contains(TestingHeader) && context.Request.Headers[TestingHeader].First().Equals(TestingHeaderValue))
        {
            // fake authenticated the user
            ClaimsIdentity claimsIdentity = new ClaimsIdentity();
            claimsIdentity.AddClaims(new List<Claim>
            {
                new Claim(ClaimTypes.Name, "admin"),
                new Claim(ClaimTypes.NameIdentifier, UserSeedData.AdminUserId)
            });
            ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
            context.User = claimsPrincipal;
        }
        await _next(context);
    }
}

主体已设置并存在于具有给定ID的数据库中,但在我调用next(context)后,我得到了401 Unauthorized结果。

如何在为HttpRequest设置当前用户的同时,成功地伪造用户身份并绕过[授权]?

更新:如果我注册自己的CookieAuthentication处理程序,如下所示:

app.UseCookieAuthentication(options =>
{
    options.AuthenticationScheme = AuthenticatedTestRequestMiddleware.TestingCookieAuthentication;
    options.AutomaticAuthenticate = true;
    options.AutomaticChallenge = true;
});

我把302 Redirect拿到登录页面。然而,当我在TestMiddleware await context.Authentication.SignInAsync(TestingCookieAuthentication, claimsPrincipal) 中使用签名时,签名工作正常

好的,所以我发现了它不起作用的原因:)

创建ClaimsPrincipal时,AuthenticationProvider必须包含在主体的构造函数中。如果未提供身份验证类型,则SignInAsync()功能将失败,并且不会对用户进行身份验证。

而不是这样做:

ClaimsIdentity claimsIdentity = new ClaimsIdentity(new List<Claim>
{
    new Claim(ClaimTypes.Name, "admin"),
    new Claim(ClaimTypes.NameIdentifier, UserSeedData.AdminUserId)
});

您必须这样指定AuthenticationHandler:

ClaimsIdentity claimsIdentity = new ClaimsIdentity(new List<Claim>
{
    new Claim(ClaimTypes.Name, "admin"),
    new Claim(ClaimTypes.NameIdentifier, UserSeedData.AdminUserId)
}, TestingCookieAuthentication);

最新更新