AspNetCore.Authentication.JwtBearer在使用.NET Core RC2时出现“无可用的SecurityTokenValidator”错误。

21

我正在尝试使用AspNew.Security.OpenIdConnect.Server发出和消耗JWT令牌的简单端点,以发出令牌,并使用Microsoft.AspNetCore.Authentication.JwtBearer进行验证。

我可以成功生成令牌,但尝试验证令牌时失败,显示错误未经授权的承载者。 失败消息:无法为令牌找到SecurityTokenValidator:{token}

此时,我已将所有内容剥离,只保留以下内容:

project.json

{
  "dependencies": {
    "Microsoft.AspNetCore.Mvc": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-rc2-final",
    "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0-rc2-final",
    "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0-rc2-final",
    "Microsoft.Extensions.Configuration.Json": "1.0.0-rc2-final",
    "Microsoft.Extensions.Logging": "1.0.0-rc2-final",
    "Microsoft.Extensions.Logging.Console": "1.0.0-rc2-final",
    "Microsoft.Extensions.Logging.Debug": "1.0.0-rc2-final",
    "AspNet.Security.OAuth.Validation": "1.0.0-alpha1-final",
    "AspNet.Security.OpenIdConnect.Server": "1.0.0-beta5-final",
    "Microsoft.AspNetCore.Authentication": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Authentication.JwtBearer": "1.0.0-rc2-final"
  },

  "tools": {
    "Microsoft.AspNetCore.Server.IISIntegration.Tools": {
      "version": "1.0.0-preview1-final",
      "imports": "portable-net45+win8+dnxcore50"
    }
  },

  "frameworks": {
    "net461": { }
  },

  "buildOptions": {
    "emitEntryPoint": true,
    "preserveCompilationContext": true
  },

  "publishOptions": {
    "include": [
      "wwwroot",
      "Views",
      "appsettings.json",
      "web.config"
    ]
  },

  "scripts": {
    "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
  }
}

Startup.cs 的方法:

// This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddAuthorization(options =>
                {
                    options.AddPolicy(JwtBearerDefaults.AuthenticationScheme,
                        builder =>
                        {
                            builder.
                            AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme).
                            RequireAuthenticatedUser().
                            Build();
                        }
                    );
                }
            );

            services.AddAuthentication();
            services.AddDistributedMemoryCache();
            services.AddMvc();
            services.AddOptions();
        }

        // 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();

            var jwtOptions = new JwtBearerOptions()
            {
                AuthenticationScheme = JwtBearerDefaults.AuthenticationScheme,
                AutomaticAuthenticate = true,
                Authority = "http://localhost:5000/",
                Audience = "http://localhost:5000/",
                RequireHttpsMetadata = false
            };

            jwtOptions.ConfigurationManager = new ConfigurationManager<OpenIdConnectConfiguration>
                (
                    metadataAddress: jwtOptions.Authority + ".well-known/openid-configuration",
                    configRetriever: new OpenIdConnectConfigurationRetriever(),
                    docRetriever: new HttpDocumentRetriever { RequireHttps = false }
                );


            app.UseJwtBearerAuthentication(jwtOptions);

            app.UseOpenIdConnectServer(options =>
            {
                options.AllowInsecureHttp = true;
                options.AuthorizationEndpointPath = Microsoft.AspNetCore.Http.PathString.Empty;
                options.Provider = new OpenIdConnectServerProvider
                {
                    OnValidateTokenRequest = context =>
                    {
                        context.Skip();
                        return Task.FromResult(0);
                    },

                    OnGrantResourceOwnerCredentials = context =>
                    {
                        var identity = new ClaimsIdentity(context.Options.AuthenticationScheme);
                        identity.AddClaim(ClaimTypes.NameIdentifier, "[unique id]");

                        identity.AddClaim("urn:customclaim", "value", OpenIdConnectConstants.Destinations.AccessToken, OpenIdConnectConstants.Destinations.IdentityToken);

                        var ticket = new AuthenticationTicket(
                            new ClaimsPrincipal(identity),
                            new Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties(),
                            context.Options.AuthenticationScheme);

                        ticket.SetScopes("profile", "offline_access");

                        context.Validate(ticket);

                        return Task.FromResult(0);
                    }
                };
            });            

            app.UseMvc();
        }

http://localhost:5000 发送 x-url-encoded POST 请求,使用 grant_type=password、username=foo 和 password=bar 参数,生成预期的 access_token。

我已将 [Authorize("Bearer")] 属性添加到 ValuesController 中,并且在 JwtBearerMiddlewear 调用时它按预期工作,但我无法获取令牌进行验证。

有人能在 .net core RC2 上使其正常工作吗?我已经在 RC1 上完成了相同的事情,但一直无法实现。

谢谢。

2个回答

15
从beta5开始(适用于ASP.NET Core RC2),OpenID Connect服务器中间件不再使用JWT作为访问令牌的默认格式。相反,它使用模糊令牌,由坚如磐石的ASP.NET Core Data Protection堆栈加密(就像身份验证Cookie一样)。
你有3个选项来解决你看到的错误:
  • 使用新的OAuth2验证中间件来支持模糊令牌(如果你的API和授权服务器是同一个应用程序,则建议选择此选项)。为此,请保留project.json中的AspNet.Security.OAuth.Validation参考,并将app.UseJwtBearerAuthentication(...)替换为app.UseOAuthValidation()。你也可以从project.json中删除Microsoft.AspNetCore.Authentication.JwtBearer

  • 通过在选项中调用options.AccessTokenHandler = new JwtSecurityTokenHandler();来强制OpenID Connect服务器中间件使用JWT令牌。请注意,您还必须调用ticket.SetResources(...)将适当的观众与JWT令牌附加在一起(有关更多信息,请参见这个Stack Overflow帖子)。

  • 使用新的内省中间件。此选项更加复杂,并需要实现ValidateIntrospectionRequest事件来验证客户端凭据。只有在您知道自己在做什么时才使用它。

如果您决定使用内省(introspection)功能,则需要的包是在这里,而不是AspNet.Security.OAuth.Extensions - paulio
这似乎非常版本特定。 - DanielV

3

顺便提一句,如果有人遇到了同样的错误(No SecurityTokenValidator available for token):

请再次确认客户端发送的身份验证标头是否处于正确的格式:

Authorize: Bearer [ey....]

No SecurityTokenValidator available for token error 表示请求中授权头的格式没有注册的处理程序。例如,如果收到的请求包含标题值 "Bearer Bearer ey82383..." 或者 "Bearer" 关键字被省略或拼写错误,则会出现此错误。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接