带有IdentityServer3.AccessTokenValidation的.Net核心上的WebAPI 2.2会抛出NullreferenceException

时间:2017-03-28 09:29:44

标签: asp.net-web-api dependency-injection asp.net-core identityserver3 owin-middleware

我很难让这个工作。目前我已经有了一个IdentityServer4,一个Angular2SPA和一个用于ODATA运行的WebAPI 2.2。所有服务都在asp.net核心的各个项目中运行。

  • IdentityServer4
  • Angular2SPA
  • WebAPI2.2。核心目标.Net462

只要我不尝试将其连接到IdentityServer,WebAPI就可以正常运行。 我已经验证我的设置在WebAPI旁边正常工作。 我还通过将他们的WebAPISample与我的IdentityServer连接,在Github上使用IdentityServer3.Samples测试了WebAPI连接配置。

的WebAPI

Startup.cs

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        //services.AddAuthorization();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(LogLevel.Debug);
        loggerFactory.AddDebug();

        app.UseOwinApp(owinApp =>
        {
            if (env.IsDevelopment())
            {
                owinApp.UseErrorPage(new ErrorPageOptions()
                {
                    ShowCookies = true,
                    ShowEnvironment = true,
                    ShowExceptionDetails = true,
                    ShowHeaders = true,
                    ShowQuery = true,
                    ShowSourceCode = true
                });
            }

            owinApp.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);

            HttpConfiguration config = new HttpConfiguration();

            JwtSecurityTokenHandler.InboundClaimTypeMap.Clear();

            owinApp.UseCookieAuthentication(new CookieAuthenticationOptions());
            owinApp.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
            {
                Authority = "https://authentication.bl.at:5000",
                RequiredScopes = new[] { "bl.API" },
                //ValidationMode = ValidationMode.ValidationEndpoint,
                //DelayLoadMetadata = true,

                //// client credentials for the introspection endpoint
                ClientId = "bl.API",
                ClientSecret = "secret"
            });


            WebAPIConfig.Register(config);


            ODataModelBuilder odataMetadataBuilder = new ODataConventionModelBuilder();
            odataMetadataBuilder.EntitySet<Product>("Products");
            config.MapODataServiceRoute(
                routeName: "ODataRoute",
                routePrefix: "odata",
                model: odataMetadataBuilder.GetEdmModel());
            owinApp.UseWebApi(config);
        });
    }
}

OwinExtensions.cs

public static class OwinExtensions
{
    public static IApplicationBuilder UseOwinApp(this IApplicationBuilder aspNetCoreApp, Action<IAppBuilder> configuration)
    {
        return aspNetCoreApp.UseOwin(setup => setup(next =>
        {
            AppBuilder owinAppBuilder = new AppBuilder();

            IApplicationLifetime aspNetCoreLifetime = (IApplicationLifetime)aspNetCoreApp.ApplicationServices.GetService(typeof(IApplicationLifetime));

            AppProperties owinAppProperties = new AppProperties(owinAppBuilder.Properties);

            owinAppProperties.OnAppDisposing = aspNetCoreLifetime?.ApplicationStopping ?? CancellationToken.None;

            owinAppProperties.DefaultApp = next;

            configuration(owinAppBuilder);

            return owinAppBuilder.Build<Func<IDictionary<string, object>, Task>>();
        }));
    }
}

WebAPIConfig.cs

public class WebAPIConfig
{
    public static void Register(HttpConfiguration config)
    {

        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
        jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    }
}

例外

只要oauth被禁用,WebAPI就会按预期工作,当它启用时,它会在启动时抛出以下异常:

Unbehandelte Ausnahme: System.NullReferenceException: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.
   bei IdentityServer3.AccessTokenValidation.DiscoveryDocumentIssuerSecurityTokenProvider..ctor(String discoveryEndpoint, IdentityServerBearerTokenAuthenticationOptions options, ILoggerFactory loggerFactory)
   bei Owin.IdentityServerBearerTokenValidationAppBuilderExtensions.<>c__DisplayClass9.<ConfigureLocalValidation>b__8()
   bei System.Lazy`1.CreateValue()
   bei System.Lazy`1.LazyInitValue()
   bei Owin.IdentityServerBearerTokenValidationAppBuilderExtensions.UseIdentityServerBearerTokenAuthentication(IAppBuilder app, IdentityServerBearerTokenAuthenticationOptions options)
   bei WebAPI.Startup.<>c__DisplayClass1_0.<Configure>b__0(IAppBuilder owinApp) in C:\Users\User\Documents\visual studio 2015\Projects\TestProject\src\WebAPI\Startup.cs:Zeile 78.
   bei WebAPI.Config.OwinExtensions.<>c__DisplayClass0_0.<UseOwinApp>b__1(Func`2 next) in C:\Users\User\Documents\visual studio 2015\Projects\TestProject\src\WebAPI\Config\OwinExtensions.cs:Zeile 29.
   bei Microsoft.AspNetCore.Builder.OwinExtensions.<>c__DisplayClass0_1.<UseOwin>b__1(RequestDelegate next1)
   bei Microsoft.AspNetCore.Builder.Internal.ApplicationBuilder.Build()
   bei Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
   bei Microsoft.AspNetCore.Hosting.WebHostBuilder.Build()
   bei WebAPI.Program.Main(String[] args) in C:\Users\User\Documents\visual studio 2015\Projects\TestProject\src\WebAPI\Program.cs:Zeile 21.

我也尝试过启用delayLoadMetadata,但这会引发以下异常:

Unbehandelte Ausnahme: System.Reflection.TargetInvocationException: Ein Aufrufziel hat einen Ausnahmefehler verursacht. ---> System.NullReferenceException: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.
   bei IdentityServer3.AccessTokenValidation.IdentityServerBearerTokenValidationMiddleware..ctor(Func`2 next, IAppBuilder app, IdentityServerOAuthBearerAuthenticationOptions options, ILoggerFactory loggerFactory)
   bei lambda_method(Closure , Func`2 , IAppBuilder , IdentityServerOAuthBearerAuthenticationOptions , ILoggerFactory )
   --- Ende der internen Ausnahmestapelüberwachung ---
   bei System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   bei System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   bei System.Delegate.DynamicInvokeImpl(Object[] args)
   bei Microsoft.Owin.Builder.AppBuilder.BuildInternal(Type signature)
   bei Microsoft.Owin.Builder.AppBuilderExtensions.Build[TApp](IAppBuilder builder)
   bei WebAPI.Config.OwinExtensions.<>c__DisplayClass0_0.<UseOwinApp>b__1(Func`2 next) in C:\Users\User\Documents\visual studio 2015\Projects\TestProject\src\WebAPI\Config\OwinExtensions.cs:Zeile 31.
   bei Microsoft.AspNetCore.Builder.OwinExtensions.<>c__DisplayClass0_1.<UseOwin>b__1(RequestDelegate next1)
   bei Microsoft.AspNetCore.Builder.Internal.ApplicationBuilder.Build()
   bei Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
   bei Microsoft.AspNetCore.Hosting.WebHostBuilder.Build()
   bei WebAPI.Program.Main(String[] args) in C:\Users\User\Documents\visual studio 2015\Projects\TestProject\src\WebAPI\Program.cs:Zeile 21.

我认为这个问题可能与ILoggerFactory的.Core / Owin依赖注入有关。可能是这两者之间的生命问题?

2 个答案:

答案 0 :(得分:0)

启用DelayLoadMetadata之前和之后的例外情况不同,一个来自DiscoveryDocumentIssuerSecurityTokenProvider的构造函数,而另一个来自IdentityServerBearerTokenValidationMiddleware的构造函数

如果您查看UseIdentityServerBearerTokenAuthentication的实施情况,您会发现这两个模块都依赖loggerFactory来自此行IApplicationBuilder的<{p}}

        var loggerFactory = app.GetLoggerFactory();

我不是.net核心专家,但是你使用UseOwin扩展方法的方式对我来说有点奇怪,你的owin管道中有一个新的AppBuilder实例而不是使用现有的aspNetCoreApp,我猜是没有记录器工厂注册了新的AppBuilder实例,因此当IdentityServer3中的模块需要它时,它会被object is null炸毁例外。

您可以通过在调用IdentityServerBearerTokenValidationMiddleware之前设置断点来轻松找到,并在owinAppBuilder.GetLoggerFactory()调试窗口中手动执行Immediate以查看它是否返回任何内容

答案 1 :(得分:0)

我遇到了同样的问题,我也试过了 DelayLoadMetadata = true 选项没有任何成功。

要解决此问题,我需要在调用之前使用app.SetLoggerFactory设置默认记录器 app.UseIdentityServerBearerTokenAuthentication(GetOptions()); 为此,您可能需要刊登广告

using Microsoft.Owin.Logging;

到你的使用并且可能添加程序集引用,这会将 SetLoggerFactory 方法添加到app对象。 (这是一个扩展)。 在我的情况下,我只使用这样的默认记录器完成它:

app.SetLoggerFactory(Microsoft.Owin.Logging.LoggerFactory.Default);
app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
    {
    //some stuff
    });
);