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

时间:2015-08-13 20:42:55

标签: jwt asp.net-core-mvc

更新

Pinpoint帮助我将这个原型从发射台上移开 - 除了以下情况之外我非常接近:

{
  "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"
  ]
}
  • 启动时的中间件顺序配置方法很重要。 UseOAuthBearerAuthentication需要在UseMvc之前。 Startup.cs中的Configure方法现在显示如下:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseOAuthBearerAuthentication();      

    app.UseMvc();
}

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

为此,我非常认真地阅读了这篇文章,重新阅读了它,内化了所有的评论,然后举起了一个简单的例子。我现在可以生成一个JWT令牌,但是当我尝试调用已使用授权属性[Authorize(“Bearer”)]进行装饰的控制器操作时,收到以下消息:

  

未接受以下身份验证方案:承载

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

  • 在Visual Studio 2015中创建一个新的Web API项目(我正在使用Enterprise),选择“New Project ... Web ... ASP.NET Web Application”,然后选择“ASP”下的“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;
        }
    }
}
  • 部分型号:

Credentials.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中发出GET请求类似到http:// localhost:22553 / api / values,注意添加一个Authorization标头值“bearer YOURTOKEN”(例如bearer eyJ0eXAiOiJKV1QiLCJ ...)

  • 观察该应用响应错误:

  

System.InvalidOperationException   未接受以下身份验证方案:承载

堆栈跟踪如下:

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 个答案:

答案 0 :(得分:6)

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

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

        app.UseMvc();
    }
}