ASP.NET 5 OAuthBearerAuthentication:不接受以下身份验证方案:Bearer

Posted

技术标签:

【中文标题】ASP.NET 5 OAuthBearerAuthentication:不接受以下身份验证方案:Bearer【英文标题】:ASP.NET 5 OAuthBearerAuthentication: The following authentication scheme was not accepted: Bearer 【发布时间】:2015-11-07 00:01:13 【问题描述】:

更新:

Pinpoint 帮助我将这个原型从发射台上取下来 - 我非常接近,除了:

我需要按照these instructions 升级到 beta6 SDK。 Global.json 现在显示如下:

  "projects": [ "src", "test" ],
  "sdk": 
    "version": "1.0.0-beta6"
  

我更新了 project.json 中的引用:

  "webroot": "wwwroot",
  "version": "1.0.0-*",

  "dependencies": 
    "Microsoft.AspNet.Mvc": "6.0.0-beta6",
    "Microsoft.AspNet.Server.IIS": "1.0.0-beta6",
    "Microsoft.AspNet.Server.WebListener": "1.0.0-beta6",
    "Microsoft.AspNet.StaticFiles": "1.0.0-beta6",
    "System.IdentityModel.Tokens": "5.0.0-beta6-207211625",
    "Serilog.Framework.Logging": "1.0.0-beta-43",
    "Microsoft.AspNet.Authentication.OAuthBearer": "1.0.0-beta6"
  ,

  "commands": 
    "web": "Microsoft.AspNet.Hosting --config hosting.ini"
  ,

  "frameworks": 
    "dnx451":  
  ,

  "exclude": [
    "wwwroot",
    "node_modules",
    "bower_components"
  ],
  "publishExclude": [
    "node_modules",
    "bower_components",
    "**.xproj",
    "**.user",
    "**.vspscc"
  ]

启动的 Configure 方法中的中间件顺序很重要。 UseOAuthBearerAuthentication 需要在 UseMvc 之前。 Startup.cs 中的 Configure 方法现在如下所示:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)

    app.UseOAuthBearerAuthentication();      

    app.UseMvc();


我正在使用 ASP.NET 5 并尝试实现一个非常简单的概念证明来生成和使用 JWT 令牌。我已阅读文章here、here 和here,但this one 最符合我的需求。

为此,我非常认真的阅读了这篇文章,重读了一遍,内化了所有的cmets,然后站出了一个简单的例子。我现在可以生成 JWT 令牌,但是当我尝试调用已使用授权属性 [Authorize("Bearer")] 修饰的控制器操作时,我收到以下消息:

不接受以下身份验证方案:Bearer

由于我没有看到有关如何执行此操作的高保真 A 到 Z 示例,请考虑以下步骤来重现:

在 Visual Studio 2015(我使用的是 Enterprise)中创建一个新的 Web API 项目,方法是选择“新建项目...Web...ASP.NET Web 应用程序”,然后选择“ASP.NET”下的“Web API”选项。 NET 5 预览模板” 使用 beta 5 SDK,global.json 如下所示:

  "projects": [ "src", "test" ],
  "sdk": 
    "version": "1.0.0-beta5",
    "runtime": "clr",
    "architecture": "x86"
  

引入 JWT 令牌所需的依赖项,project.json 如下所示:

    "webroot": "wwwroot",
    "version": "1.0.0-*",

    "dependencies": 
        "Microsoft.AspNet.Mvc": "6.0.0-beta6",
        "Microsoft.AspNet.Server.IIS": "1.0.0-beta6",
        "Microsoft.AspNet.Server.WebListener": "1.0.0-beta6",
        "System.IdentityModel.Tokens": "5.0.0-beta5-206011020",
        "Microsoft.AspNet.Authentication.OAuthBearer": "1.0.0-beta5"
    ,

    "commands": 
        "web": "Microsoft.AspNet.Hosting --config hosting.ini"
    ,

    "frameworks": 
        "dnx451":  
    ,

    "exclude": [
        "wwwroot",
        "node_modules",
        "bower_components"
    ],
    "publishExclude": [
        "node_modules",
        "bower_components",
        "**.xproj",
        "**.user",
        "**.vspscc"
    ]

Startup.cs(这是一个示例不用于生产)
public class Startup

    const string        _TokenIssuer        = "contoso.com"             ;
    const string        _TokenAudience      = "contoso.com/resources"   ;
    RsaSecurityKey      _key                = null                      ;
    SigningCredentials  _signingCredentials = null                      ;

    public Startup(IHostingEnvironment env)
    
        GenerateRsaKeys();
    

    public void ConfigureServices(IServiceCollection services)
    
        services.AddInstance(_signingCredentials);

        services.ConfigureOAuthBearerAuthentication
        (
            options =>
            
                options.AutomaticAuthentication = true;
                options.TokenValidationParameters.IssuerSigningKey  = _key          ;
                options.TokenValidationParameters.ValidAudience     = _TokenAudience;
                options.TokenValidationParameters.ValidIssuer       = _TokenIssuer  ;
            
        );

        services.ConfigureAuthorization
        (
            options =>
            
                options.
                AddPolicy
                (
                    "Bearer",
                    new AuthorizationPolicyBuilder().
                        AddAuthenticationSchemes(OAuthBearerAuthenticationDefaults.AuthenticationScheme).
                        RequireAuthenticatedUser().
                        Build()
                );
            
        );

        services.AddMvc();
    

    public void Configure(IApplicationBuilder app, IHostingEnvironment env,ILoggerFactory loggerfactory)
    
        app.UseMvc();

        app.UseOAuthBearerAuthentication();
    

    void GenerateRsaKeys()
    
        using(RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(2048))
        
            _key = new RsaSecurityKey(rsa.ExportParameters(true));

            _signingCredentials = 
                new SigningCredentials
                (
                    _key                                    , 
                    SecurityAlgorithms.RsaSha256Signature   , 
                    SecurityAlgorithms.Sha256Digest         ,
                    "secret"
                );

            rsa.PersistKeyInCsp = false;
        
    

部分型号:

凭据.cs

public class Credentials

    public string user  set;get;
    public string password  set;get;

JwtToken.cs

public class JwtToken

    public string access_token   set; get; 
    public string token_type     set; get; 

用于获取令牌的令牌控制器(这是一个不用于生产的示例),TokenController.cs:
[ Route("[controller]") ]
public class TokenController : Controller

    private readonly OAuthBearerAuthenticationOptions   _bearerOptions      ;
    private readonly SigningCredentials                 _signingCredentials ;

    public TokenController
    (
        IOptions<OAuthBearerAuthenticationOptions>  bearerOptions       ,
        SigningCredentials                          signingCredentials
    )
    
        _bearerOptions      = bearerOptions.Options ;
        _signingCredentials = signingCredentials    ;
    

    // POST: /token
    [HttpPost()]
    public JwtToken Token([FromBody] Credentials credentials)
    
        // Pretend to validate credentials...

        JwtSecurityTokenHandler handler = 
            _bearerOptions                      .
            SecurityTokenValidators             .
            OfType<JwtSecurityTokenHandler>()   .
            First();

        JwtSecurityToken securityToken = 
            handler     .
            CreateToken
            (
                issuer              : _bearerOptions.TokenValidationParameters.ValidIssuer  ,
                audience            : _bearerOptions.TokenValidationParameters.ValidAudience,
                signingCredentials  : _signingCredentials                                   ,
                subject             : new ClaimsIdentity
                (
                    new Claim [] 
                    
                        new Claim(ClaimTypes.Name,"somebody"),
                        new Claim(ClaimTypes.Role,"admin"   ),
                        new Claim(ClaimTypes.Role,"teacher" ),
                    
                ) ,
                expires             : DateTime.Today.AddDays(1)
            );

        string token = handler.WriteToken(securityToken);

        return new JwtToken()
        
            access_token    = token     ,
            token_type      = "bearer"
        ;
    

用于演示提取令牌的值控制器,ValuesController.cs:
[Route("api/[controller]")]
public class ValuesController : Controller

    // GET: api/values
    [Authorize("Bearer")]
    [HttpGet]
    public IEnumerable<string> Get()
    
        return new string[]  "value1", "value2" ;
    

    // GET api/values/5
    [HttpGet("id")]
    public string Get(int id)
    
        return "value";
    

启动postman(或您最喜欢的 REST 客户端)的副本,在 Visual Studio 下启动示例应用程序并发出 POST 请求,类似于 http://localhost:22553/token / 带有 JSON 正文:

    "user" : "user",
    "password" : "secret"

应用以令牌响应:


  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6bnVsbH0.eyJ1bmlxdWVfbmFtZSI6InNvbWVib2R5Iiwicm9sZSI6WyJhZG1pbiIsInRlYWNoZXIiXSwiaXNzIjoiY29udG9zby5jb20iLCJhdWQiOiJjb250b3NvLmNvbS9yZXNvdXJjZXMiLCJleHAiOjE0Mzk1MzU2MDB9.anRgL10XFG_bKDDxY3D2xQSfhPRLGMjUTreQNsP1jDA6eRKwXHf3jtpCwm_saoWyUDFFA2TMI9e_LbP6F5l7vtozCluziE_GQkPkspUSWuWIpQJLPRTTPPZHGKmPmK4MLEl1zPPrggJWbvF9RBw3mMQ0KoMfjSL0vUQ8kZ7VXAel8dnYJccd-CFdnB6aDe79x2E9Se2iLxdhr--R_qgvfz1Fa6tR1dstqLQ-UjYqPWY4SOgBjM3abtjfLLVEzeQMVyezX7Cx9ObMXAGbGvQL6GB_T5RlfAoXWME4jM8Bzhd-07wwd732bBws4OXivj1sSz-qawNTnXmnuccLRtI1uA",
  "token_type": "bearer"

从上一个 POST 中复制令牌,然后在 postman 中发出 类似 到 http://localhost:22553/api/values 的 GET 请求,注意添加一个 Authorization 标头值“承载 YOURTOKEN”(例如承载 eyJ0eXAiOiJKV1QiLCJ...)

观察应用程序响应错误:

System.InvalidOperationException 不接受以下身份验证方案:Bearer

堆栈跟踪如下:

at Microsoft.AspNet.Http.Authentication.Internal.DefaultAuthenticationManager.< AuthenticateAsync> d__9.MoveNext() 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at Microsoft.AspNet.Http.Authentication.AuthenticationManager.< AuthenticateAsync> d__2.MoveNext()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter< TResult> .GetResult() 
at Microsoft.AspNet.Mvc.AuthorizeFilter.< OnAuthorizationAsync> d__5.MoveNext() 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at Microsoft.AspNet.Mvc.Core.FilterActionInvoker.< InvokeAuthorizationFilterAsync> d__43.MoveNext()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at Microsoft.AspNet.Mvc.Core.FilterActionInvoker.< InvokeAllAuthorizationFiltersAsync> d__42.MoveNext() 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at Microsoft.AspNet.Mvc.Core.FilterActionInvoker.< InvokeAsync> d__40.MoveNext() 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at Microsoft.AspNet.Mvc.MvcRouteHandler.< InvokeActionAsync> d__4.MoveNext() 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at Microsoft.AspNet.Mvc.MvcRouteHandler.< RouteAsync> d__3.MoveNext() 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at Microsoft.AspNet.Mvc.Routing.InnerAttributeRoute.< RouteAsync> d__10.MoveNext() 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at Microsoft.AspNet.Routing.RouteCollection.< RouteAsync> d__9.MoveNext() 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at Microsoft.AspNet.Builder.RouterMiddleware.< Invoke> d__4.MoveNext() 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at Microsoft.AspNet.Hosting.Internal.RequestServicesContainerMiddleware.< Invoke> d__3.MoveNext() 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at Microsoft.AspNet.Hosting.Internal.HostingEngine.< > c__DisplayClass29_0.< < Start> b__0> d.MoveNext() 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at Microsoft.AspNet.Loader.IIS.RuntimeHttpApplication.< ProcessRequestAsyncImpl> d__10.MoveNext() 
--- exception rethrown --- 
at Microsoft.AspNet.Loader.IIS.RuntimeHttpApplication.< ProcessRequestAsyncImpl> d__10.MoveNext() 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at Microsoft.AspNet.Loader.IIS.HttpApplicationBase.< InvokeProcessRequestAsyncImpl> d__9.MoveNext()

请注意,添加日志记录几乎不会增加额外的洞察力,如以下日志所示:

2015-08-13 13:32:35.969 -07:00 [Information] Request successfully matched the route with name 'null' and template '"api/Values"'.
Exception thrown: 'System.InvalidOperationException' in Microsoft.AspNet.Http.dll
2015-08-13 13:32:36.247 -07:00 [Error] An error occurred while handling the request.
2015-08-13 13:32:36.247 -07:00 System.InvalidOperationException: The following authentication scheme was not accepted: Bearer

我希望有人能理解这个例子中的故障发生在哪里。

【问题讨论】:

【参考方案1】:

您必须在MVC之前注册OAuth2承载认证中间件,否则您的用户在到达MVC时将无法认证:

public class Startup 
    public void Configure(IApplicationBuilder app) 
        app.UseJwtBearerAuthentication(new JwtBearerOptions 
            // Your JWT bearer options.
        );

        app.UseMvc();
    

【讨论】:

非常感谢您的观察。我以前尝试过这种方法,但假设我犯了一个错误,因为当我尝试调用我的任何控制器方法时收到以下错误:[错误] 处理请求时发生错误。 System.TypeLoadException:来自程序集“Microsoft.AspNet.Authentication.OAuthBearer,版本=1.0.0.0,文化=中性,PublicKeyToken=null”的“Microsoft.AspNet.Authentication.OAuthBearer.OAuthBearerAuthenticationHandler”类型中的方法“ChallengeAsync”没有实施。 此错误可能是由于您在同一应用程序中引用了 beta5 和 beta6 包。确保将所有内容迁移到 beta6(甚至是 DNX 运行时),它应该可以工作。 谢谢,Pinpoint - 这就是确切的答案。我按照 this article 升级了我的 Visual Studio 工具,现在我可以生成和摄取 JWT 令牌。我将编辑原始帖子以反映这些更改。 @Pinpoint,这对你适用于 beta8 吗?对于 beta8,我得到状态 500 和异常 'System.MissingMethodException: Method not found: '!!0 Microsoft.AspNet.Http.HttpContext.GetFeature()'.'。知道如何解决这个问题吗? @AntonS 确保您的 beta8 软件包都具有相同的夜间版本。已向 aspnet/HttpAbstractions 添加大量重大更改。

以上是关于ASP.NET 5 OAuthBearerAuthentication:不接受以下身份验证方案:Bearer的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET 5

ASP.NET 5 改名 ASP.NET Core 1.0

ASP.NET Core 托管捆绑包 5 是不是也可以运行 .NET/ASP.NET Core 2.1 应用程序?

ASP.NET 5 - 启动 ASP.NET vNext 项目

ASP.NET 5 简介 MVC

ASP.net 5主要改进