ASP.NET Core JWTBearerAuthentication未正确验证/授权

时间:2017-07-31 03:27:06

标签: c# asp.net asp.net-core

问题我在signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes("secret")), SecurityAlgorithms.HmacSha256)使用TokenController时,我500 Internal Server Error获得var encoded_token = new System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler().WriteToken(token);

我认为这可能与适当的证书有关。

当我删除该行并转到http://localhost:61571/api/Users时,我会收到401 Unauthorized状态代码。当我将其插入在线解码器时,创建的JWT似乎工作正常。

所以我的问题是:

  1. 为什么JwtSecurityTokenHandler().WriteToken(token);给我500个内部服务器错误?
  2. 为什么我会收到401 Unauthorized代码?
  3. 我使用VS2017和ASP.NET Core 1.1。这一切都在VS2017中的IIS Express上运行。

    Startup.cs

    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Logging;
    using Microsoft.EntityFrameworkCore;
    using ToDoApi.Services;
    
    using Microsoft.AspNetCore.Http;
    using Microsoft.IdentityModel.Tokens;
    using System.Text;
    using System;
    
    namespace ToDoApi
    {
        public class Startup
        {
            public Startup(IHostingEnvironment env)
            {
                var builder = new ConfigurationBuilder()
                    .SetBasePath(env.ContentRootPath)
                    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                    .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                    .AddEnvironmentVariables();
                Configuration = builder.Build();
            }
    
            public IConfigurationRoot Configuration { get; }
    
            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddDbContext<ToDoApi.Data.ApplicationDbContext>(opt => opt.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    
                services.AddSingleton<IUserService, UserService>();
    
                // Add framework services.
                services.AddMvc();
            }
    
            // 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();
    
                env.EnvironmentName = EnvironmentName.Development;
    
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                else
                {
                    app.UseExceptionHandler("/error");
                }
    
    
                var keyAsBytes = Encoding.ASCII.GetBytes("secret");
    
                var options = new JwtBearerOptions
                {
                    AutomaticAuthenticate = true,
                    AutomaticChallenge = true,
                    TokenValidationParameters = new TokenValidationParameters
                    {
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("secret")),
                        ValidateIssuerSigningKey = true,
    
                        ValidAudience = "http://localhost:61571",
                        ValidateAudience = true,
    
                        ValidIssuer = "http://localhost:61571",
                        ValidateIssuer = true,
    
                        ValidateLifetime = true,
                        ClockSkew = TimeSpan.Zero
                    }
                };
    
                app.UseJwtBearerAuthentication(options);
    
                app.UseMvc();
            }
        }
    }
    

    TokenController.cs

    using System.IdentityModel.Tokens.Jwt;
    using System.Security.Claims;
    using System.Text;
    using System.Threading.Tasks;
    using ToDoApi.Models;
    
    namespace ToDoApi.Controllers
    {
        [Produces("application/json")]
        [Route("api/[controller]")]
        public class TokenController : Controller
        {
            [HttpPost]
            public IActionResult Token([FromBody] User model)
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest();
                }
    
                var user = new User { ID = 1, Username = "username", Password = "password" };//await _userManager.FindByNameAsync(model.Email);
    
                //if (user == null || _passwordHasher.VerifyHashedPassword(user, user.PasswordHash, model.Password) != PasswordVerificationResult.Success)
                //{
                //    return BadRequest();
                // }
    
                var claims = new Claim[]
     {
                    new Claim(JwtRegisteredClaimNames.Sub, "username"),
                     new Claim(JwtRegisteredClaimNames.Jti, "40fdb6d4-1ea5-49af-9fcc-edb9e8d18dd5"),
                     new Claim(JwtRegisteredClaimNames.Iat, new DateTimeOffset(DateTime.UtcNow).ToUniversalTime().ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64)
     };
                var token = new System.IdentityModel.Tokens.Jwt.JwtSecurityToken(
                    issuer: "http://localhost:61571",
                    audience: "http://localhost:61571",
                    claims: claims,
                    notBefore: DateTime.UtcNow,
                    expires: DateTime.UtcNow.AddMinutes(10),
                    signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes("secret")), SecurityAlgorithms.HmacSha256)
                );
    
                var encoded_token = new System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler().WriteToken(token);
                return Ok(new
                {
                    token = encoded_token,
                    expiration = token.ValidTo
                });
            }
        }
    }
    

    UsersController.cs

    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.EntityFrameworkCore;
    using ToDoApi.Models;
    using ToDoApi.Services;
    using Microsoft.AspNetCore.Authorization;
    using System.IdentityModel.Tokens.Jwt;
    
    namespace ToDoApi.Controllers
    {
        [Produces("application/json")]
        [Route("api/[controller]")]
        public class UsersController : Controller
        {
            private readonly IUserService _userService;
    
            public UsersController(IUserService userService)
            {
                _userService = userService;
            }
    
            // GET: api/Users
            [Authorize]
            [HttpGet]
            public IEnumerable<User> GetUsers()
            {
                return _userService.ListAll();
            }
        }
    }
    

1 个答案:

答案 0 :(得分:0)

您获得500代码的原因可能是您使用HMACSHA256的密钥太短。尝试使用至少128位大小的字符串(16个符号)。

对于它所依赖的401代码。如果在尝试生成令牌时遇到500错误,那么您在Authorization标头中使用了哪个令牌?

401的另一个棘手原因可能是您正在使用Bearer授权以及Cookie和Identity Framework。在这种情况下,您需要在UseJwtBearerAuthentication之前致电UseIdentity。但是从您提供的代码示例中,您似乎不使用Identity。