如何调试 JWT 承载错误 "invalid_token"
How to debug JWT Bearer Error "invalid_token"
我正在尝试使用 jwt 保护现有的 AspNet Core 2.0 / angular 4 应用程序。我在客户端使用 angular2-jwt,它工作得很好。但是,当涉及到我的 WebApi 时,我的令牌总是被拒绝(使用 angular2-jwt 中的 AuthHttp 来启动我的请求,甚至使用邮递员)。我得到的唯一响应是 401 Bearer error="invalid_token"。我用 jwt.io chrome 扩展名检查过它,它看起来很好(签名、观众、发行人)。我在 IIS 日志中找不到任何关于它被视为无效的原因。所以我的问题是如何获得有关令牌问题的更多信息?
任何帮助将不胜感激。
我的startup.cs
供参考
public class Startup
{
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
host.Run();
}
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, 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)
{
IConfigurationSection jwtConf = this.Configuration.GetSection("jwt");
services.Configure<Controls.JWTConf>(Configuration.GetSection("jwt"));
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters =
new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = jwtConf.GetValue<string>("issuer"),
ValidAudience = jwtConf.GetValue<string>("audience"),
IssuerSigningKey = Security.JwtSecurityKey.Create(jwtConf.GetValue<string>("keyBase"))
};
});
services.AddMvc(
config =>
{
var policy = new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
.RequireClaim(ClaimTypes.Name)
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
}
).AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());
services.AddNodeServices();
string conn = this.Configuration.GetConnectionString("optimumDB");
services.AddDbContext<TracDbContext>(options =>
options.UseSqlServer(conn));
// Register the Swagger generator, defining one or more Swagger documents
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "Angular 4.0 Universal & ASP.NET Core advanced starter-kit web API", Version = "v1" });
});
}
// 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, TracDbContext context)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseStaticFiles();
app.UseAuthentication();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
{
HotModuleReplacement = true,
HotModuleReplacementEndpoint = "/dist/__webpack_hmr"
});
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
// Enable middleware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpoint.
app.MapWhen(x => !x.Request.Path.Value.StartsWith("/swagger", StringComparison.OrdinalIgnoreCase), builder =>
{
builder.UseMvc(routes =>
{
routes.MapSpaFallbackRoute(
name: "spa-fallback",
defaults: new { controller = "Home", action = "Index" });
});
});
}
else
{
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
routes.MapRoute(
"Sitemap",
"sitemap.xml",
new { controller = "Home", action = "SitemapXml" });
routes.MapSpaFallbackRoute(
name: "spa-fallback",
defaults: new { controller = "Home", action = "Index" });
});
app.UseExceptionHandler("/Home/Error");
}
}
}
我的令牌生成控制器
[Route("api/token")]
[AllowAnonymous]
public class TokenController : Controller
{
private IOptions<JWTConf> jwt;
public TokenController(IOptions<JWTConf> jwtConf)
{
this.jwt = jwtConf;
}
[HttpPost]
public IActionResult Create([FromBody]string userCode)
{
Model.Entities.Utilisateur user = new Model.Entities.Utilisateur { ID_UTILISATEUR = 6 };
JwtToken token = new JwtTokenBuilder()
.AddSecurityKey(JwtSecurityKey.Create(this.jwt.Value.keyBase))
.AddSubject("User")
.AddIssuer(this.jwt.Value.issuer)
.AddAudience(this.jwt.Value.audience)
.AddClaim(ClaimTypes.Name,user.ID_UTILISATEUR.ToString())
.AddExpiry(1440)
.Build();
var tok = new { token = token.Value };
//return Ok(token);
return Ok(JsonConvert.SerializeObject(tok));
}
}
最后是拒绝令牌的控制器:
[Produces("application/json")]
public class JobsController : BaseController
{
public JobsController(IConfiguration config, TracDbContext db) : base(config, db)
{
}
// GET: api/Jobs
[HttpGet]
[Route("api/Jobs")]
public IEnumerable<Departement> Get()
{
return new GroupedJobs(Db.GetJobs().ToList());
}
[HttpGet]
[Route("api/Jobs/{id}")]
public JOB_CLIENT Get(int id)
{
return Db.GetDetailsJob(id);
}
}
发现问题...原来我在存储我的令牌时用引号括起来。所以发送的授权 header 看起来像这样
Bearer "TOKEN"
而不是
Bearer TOKEN
我对整个事情都不熟悉,我认为引号是由 AuthHtpp 添加的,并且是协议的一部分。
我正在尝试使用 jwt 保护现有的 AspNet Core 2.0 / angular 4 应用程序。我在客户端使用 angular2-jwt,它工作得很好。但是,当涉及到我的 WebApi 时,我的令牌总是被拒绝(使用 angular2-jwt 中的 AuthHttp 来启动我的请求,甚至使用邮递员)。我得到的唯一响应是 401 Bearer error="invalid_token"。我用 jwt.io chrome 扩展名检查过它,它看起来很好(签名、观众、发行人)。我在 IIS 日志中找不到任何关于它被视为无效的原因。所以我的问题是如何获得有关令牌问题的更多信息? 任何帮助将不胜感激。
我的startup.cs
供参考public class Startup
{
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
host.Run();
}
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, 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)
{
IConfigurationSection jwtConf = this.Configuration.GetSection("jwt");
services.Configure<Controls.JWTConf>(Configuration.GetSection("jwt"));
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters =
new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = jwtConf.GetValue<string>("issuer"),
ValidAudience = jwtConf.GetValue<string>("audience"),
IssuerSigningKey = Security.JwtSecurityKey.Create(jwtConf.GetValue<string>("keyBase"))
};
});
services.AddMvc(
config =>
{
var policy = new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
.RequireClaim(ClaimTypes.Name)
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
}
).AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());
services.AddNodeServices();
string conn = this.Configuration.GetConnectionString("optimumDB");
services.AddDbContext<TracDbContext>(options =>
options.UseSqlServer(conn));
// Register the Swagger generator, defining one or more Swagger documents
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "Angular 4.0 Universal & ASP.NET Core advanced starter-kit web API", Version = "v1" });
});
}
// 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, TracDbContext context)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseStaticFiles();
app.UseAuthentication();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
{
HotModuleReplacement = true,
HotModuleReplacementEndpoint = "/dist/__webpack_hmr"
});
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
// Enable middleware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpoint.
app.MapWhen(x => !x.Request.Path.Value.StartsWith("/swagger", StringComparison.OrdinalIgnoreCase), builder =>
{
builder.UseMvc(routes =>
{
routes.MapSpaFallbackRoute(
name: "spa-fallback",
defaults: new { controller = "Home", action = "Index" });
});
});
}
else
{
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
routes.MapRoute(
"Sitemap",
"sitemap.xml",
new { controller = "Home", action = "SitemapXml" });
routes.MapSpaFallbackRoute(
name: "spa-fallback",
defaults: new { controller = "Home", action = "Index" });
});
app.UseExceptionHandler("/Home/Error");
}
}
}
我的令牌生成控制器
[Route("api/token")]
[AllowAnonymous]
public class TokenController : Controller
{
private IOptions<JWTConf> jwt;
public TokenController(IOptions<JWTConf> jwtConf)
{
this.jwt = jwtConf;
}
[HttpPost]
public IActionResult Create([FromBody]string userCode)
{
Model.Entities.Utilisateur user = new Model.Entities.Utilisateur { ID_UTILISATEUR = 6 };
JwtToken token = new JwtTokenBuilder()
.AddSecurityKey(JwtSecurityKey.Create(this.jwt.Value.keyBase))
.AddSubject("User")
.AddIssuer(this.jwt.Value.issuer)
.AddAudience(this.jwt.Value.audience)
.AddClaim(ClaimTypes.Name,user.ID_UTILISATEUR.ToString())
.AddExpiry(1440)
.Build();
var tok = new { token = token.Value };
//return Ok(token);
return Ok(JsonConvert.SerializeObject(tok));
}
}
最后是拒绝令牌的控制器:
[Produces("application/json")]
public class JobsController : BaseController
{
public JobsController(IConfiguration config, TracDbContext db) : base(config, db)
{
}
// GET: api/Jobs
[HttpGet]
[Route("api/Jobs")]
public IEnumerable<Departement> Get()
{
return new GroupedJobs(Db.GetJobs().ToList());
}
[HttpGet]
[Route("api/Jobs/{id}")]
public JOB_CLIENT Get(int id)
{
return Db.GetDetailsJob(id);
}
}
发现问题...原来我在存储我的令牌时用引号括起来。所以发送的授权 header 看起来像这样
Bearer "TOKEN"
而不是
Bearer TOKEN
我对整个事情都不熟悉,我认为引号是由 AuthHtpp 添加的,并且是协议的一部分。