.net核心集成测试:API控制器操作未从测试调用。如何在测试项目中模拟opeind连接认证?

时间:2018-10-26 12:48:56

标签: c# .net .net-core openid openid-connect

启动cs文件.net核心:(创建测试服务器时也会调用该文件)

 public class Startup
{
    private IHostingEnvironment env;
    private Dictionary<string, string> secretlist = new Dictionary<string, string>();

    public Startup(IConfiguration configuration, IHostingEnvironment env)
    {         
        this.Configuration = configuration;
        this.CurrentEnvironment = env;

    }

    public Startup(IHostingEnvironment env)
    {
        this.env = env;
    }

    public IConfiguration Configuration { get; }

    private IHostingEnvironment CurrentEnvironment { get; set; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<FormOptions>(x =>
        {
            x.ValueLengthLimit = int.MaxValue;
            x.MultipartBodyLengthLimit = int.MaxValue;
            x.MultipartHeadersLengthLimit = int.MaxValue;
        });

        services.AddApplicationInsightsTelemetry(this.Configuration);
        services.AddSingleton<ITelemetryInitializer, AppInsightsInitializer>();

        // Adds services required for using options.
        services.AddOptions();

        services.Configure<AppSettingsConfig>(this.Configuration.GetSection("AppSettings"));

        if (this.CurrentEnvironment.IsDevelopment())
        {
            services.AddDataProtection()
               .PersistKeysToFileSystem(new DirectoryInfo(Environment.ExpandEnvironmentVariables(this.Configuration.GetValue<string>("AppSettings:KeyStorage_UNCPath"))))
               .ProtectKeysWithDpapiNG();
        }
        else
        {
            CloudStorageAccount storageAccount = new CloudStorageAccount(
                new Microsoft.WindowsAzure.Storage.Auth.StorageCredentials(
                                                 this.Configuration.GetValue<string>("AppSettings:StorageAccountName"),
                                                this.Configuration.GetValue<string>("AppSettings:StorageAccessValue")), true);

            //Create blob client
            CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
            // Get a reference to a container named "keycontainer."
            CloudBlobContainer container = blobClient.GetContainerReference("keycontainer");
            services.AddDataProtection().PersistKeysToAzureBlobStorage(container, "keys.xml");
        }

        services.Configure<AppSettingsConfig>(options =>
        {
            if (!this.CurrentEnvironment.IsDevelopment())
            {

            }
        });

        var azureAdConfig = new AzureAdConfig();
        this.Configuration.GetSection("Authentication:AzureAd").Bind(azureAdConfig);
        services.Configure<AzureAdConfig>(this.Configuration.GetSection("Authentication:AzureAd"));

        var connectionStringsConfig = new ConnectionStringsConfig();
        connectionStringsConfig.oneConnection = this.secretlist["ConnectionStrings"];
        //this.Configuration.GetSection("ConnectionStrings").Bind(connectionStringsConfig);
        //services.Configure<ConnectionStringsConfig>(this.Configuration.GetSection("ConnectionStrings"));



        if (this.RequireAAD())
        {
            // Add framework services.
            services.Configure<MvcOptions>(options =>
            {
                options.Filters.Add(new RequireHttpsAttribute());
            });
        }
        else
        {
            services.Configure<MvcOptions>(options =>
            {
            });
        }

        // Add Authentication services.
        if (this.RequireAAD())
        {
            // Configure the OWIN pipeline to use cookie auth.
            services.AddAuthentication(options =>
            {
                options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
            })
            .AddCookie()
            // Configure the OWIN pipeline to use OpenID Connect auth.
            // https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-openid-connect-code
            .AddOpenIdConnect(options =>
            {
                options.ClientId = azureAdConfig.ClientId;
                options.ClientSecret = azureAdConfig.ClientSecret;
                options.Authority = string.Format(azureAdConfig.AADInstance, azureAdConfig.Tenant);
                options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
                options.Resource = azureAdConfig.ResourceURI_Graph;
                // PostLogoutRedirectUri = Configuration["AzureAd:PostLogoutRedirectUri"],
                options.Events = new AuthEvents(azureAdConfig, connectionStringsConfig);
            });




        if (this.RequireAAD())
        {
            services.AddMvc(config =>
            {
                var policy = new AuthorizationPolicyBuilder()
                                 .RequireAuthenticatedUser()
                                 .Build();
                config.Filters.Add(new Microsoft​.AspNetCore​.Mvc​.Authorization.AuthorizeFilter(policy));
                config.Filters.Add(typeof(ExceptionFilter));
            });
        }
        else
        {
            services.AddMvc();
        }
        if (this.Configuration.GetValue<bool>("API: SWITCH_ENABLE_API", true))
        {
            //services.AddScoped<IDBOperation, Operations>();
            services.AddScoped<ILookupSearch, Operations>();
            services.AddScoped<IFullSearch, Operations>();
        }

        services.AddSingleton<Common.Data.RepositoryFactories>(new Common.Data.RepositoryFactories(new Dictionary<Type, Func<DbContext, object>>
            {
                { typeof(IQueryRepository), dbcontext => new QueryRepository(dbcontext) },
                { typeof(IDomainValuesRepository), dbcontext => new DomainValuesRepository(dbcontext) },
                { typeof(IRequestsRepository), dbcontext => new RequestsRepository(dbcontext) },

                // { typeof(IoneDomainValuesRepository), dbcontext => new oneDomainValuesRepository(dbcontext) }
        }));

        services.AddTransient<Common.Contracts.IRepositoryProvider, Common.Data.RepositoryProvider>();
        services.AddScoped<one.Data.Contracts.IoneUow, one.Data.oneUow>();
        services.AddTransient<IUow,Uow>();
        // For accessing appinsights for dependency injection?
        services.AddApplicationInsightsTelemetry();

        // For Storing Tokens in DB
        services.AddDistributedSqlServerCache(o =>
        {
            o.ConnectionString = this.secretlist["ConnectionStrings"];
           // o.ConnectionString = this.Configuration.GetConnectionString("oneConnection");
            // o.ConnectionString = this.Configuration[this.Configuration.GetSection("KeyVaultSeetings")["oneConnectionString"]];
            o.SchemaName = "dbo";
            o.TableName = "CacheTable";
        });
        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        services.AddSingleton<IEntityExtractor, EntityExtractor>();
        services.AddScoped<ITokenCacheService, DistributedTokenCacheService>();
        services.AddScoped<ITokenService, TokenService>();
        services.AddTransient<IAPIClient,APIClient>();
    }

    /// <summary>
    ///  This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    /// </summary>
    /// <param name="app"></param>
    /// <param name="env"></param>
    /// <param name="loggerFactory"></param>
    /// <param name="tc"></param>
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, TelemetryClient tc)
    {
        var azureAdConfig = new AzureAdConfig();
        this.Configuration.GetSection("Authentication:AzureAd").Bind(azureAdConfig);
        loggerFactory.AddConsole(this.Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();
        loggerFactory.AddProvider(new MyFilteredLoggerProvider(tc));
        loggerFactory.AddApplicationInsights(app.ApplicationServices, this.Configuration.GetValue<string>("Logging:LogLevel:Default") == "Information" ? Microsoft.Extensions.Logging.LogLevel.Information : Microsoft.Extensions.Logging.LogLevel.Warning);

        this.SetupStore(app);

        app.UseRewriter(new RewriteOptions().AddRedirectToHttps());

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
            {
                HotModuleReplacement = true
            });
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }

        // TODO . Switch
        app.UseStaticFiles();

        if (this.RequireAAD())
        {
            app.UseAuthentication();
        }

        app.UseMiddleware(typeof(ErrorHandlingMiddleware));
        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");

            routes.MapSpaFallbackRoute(
                name: "spa-fallback",
                defaults: new { controller = "Home", action = "Index" });
        });
    }

}

控制器装饰为:

 [Route("api/[controller]")]
    public class SearchController : BaseController

Controller Action装饰为:

[Route("TestMethod")]
        [ActionName("TestMethod")]
        [HttpGet]
        public async Task<EmptyResult> Test()

TestServer Test CS文件的配置:

    public DemoTest()
     {
        // Set up server configuration
        var configuration = new ConfigurationBuilder()                                                              
                            .AddJsonFile(@"appsettings.json")
                            .Build();
        // Create builder
        var builder = new WebHostBuilder()                                                     
                        .UseStartup<Startup>()
                        .UseConfiguration(configuration);
        // Create test server
        var server = new TestServer(builder);
        // Create database context
        this._context = server.Host.Services.GetService(typeof(DBContext)) as DBContext;

        // Create client to query server endpoints
        this._client = server.CreateClient();
        _client.BaseAddress = new Uri("https://localhost:44316/");
}

事实测试:

  [Fact]
    public async Task Test()
    {
        try
        {

            var response = await this._client.GetAsync("/api/Search/TestMethod");
            response.EnsureSuccessStatusCode();
            var responseString = await response.Content.ReadAsStringAsync();
            //Assert.False(result != null);
        }
        catch (Exception ex)
        {
            throw;
        }

    }
  

获取状态为302并且SearchController操作未获取   叫。使用启动配置解决所有依赖关系   文件

任何想法???

1 个答案:

答案 0 :(得分:-1)

您可以检查var responseString = await response.Content.ReadAsStringAsync();的内容以查看内容。

我认为这是登录页面,原因是您需要Authorize

首先,尝试删除下面的代码以进行尝试。

services.AddMvc(config =>
        {
            //var policy = new AuthorizationPolicyBuilder()
                             .RequireAuthenticatedUser()
                             .Build();
            //config.Filters.Add(new Microsoft​.AspNetCore​.Mvc​.Authorization.AuthorizeFilter(policy));
            config.Filters.Add(typeof(ExceptionFilter));
        });

对于Authentication,您需要模仿登录过程,这是Identity的链接,您可以尝试实现自己的AAD登录。

Razor Pages .NET Core 2.1 Integration Testing post authentication