我遇到的问题是当我在TokenController
中使用signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes("secret")), SecurityAlgorithms.HmacSha256)
时,我在var encoded_token = new System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler().WriteToken(token);
得到500 Internal Server Error
。
我相信这可能与适当的证书有关。
当我删除该行并转到http://localhost:61571/api/Users
时,我得到一个401 Unauthorized
状态代码。 当我将其插入在线解码器时,创建的 JWT 似乎工作正常。
所以我的问题是:
- 为什么
JwtSecurityTokenHandler().WriteToken(token);
给我一个 500 内部服务器错误? - 为什么我会收到 401 未授权代码?
我正在使用带有 ASP.NET 酷1.1的VS2017。 这一切都在VS2017的IIS Express上运行。
启动.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();
}
}
}
令牌控制器.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
});
}
}
}
用户控制器.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();
}
}
}
您获得 500 代码的原因可能是您使用了太短的密钥来HMACSHA256
。尝试使用至少 128 位大小(16 个符号(的字符串。
对于 401 代码,这取决于。如果在尝试生成令牌时收到 500 错误,则在授权标头中使用什么令牌?
401的另一个棘手原因可能是您正在使用Bearer
授权以及Cookie和身份框架。在这种情况下,您需要在UseIdentity
之前呼叫UseJwtBearerAuthentication
。但从您提供的代码示例中,您似乎不使用 Identity。