I've been trying to develop a simple Web API with the JWT Bearer Authentication. So far I already have an application fully developed, and now I need a web API to provide communication with other technologies.
To begin my API I found this tutorial here that provides a simple example: https://medium.com/@renato.groffe/asp-net-core-2-0-autentica%C3%A7%C3%A3o-em-apis-utilizando-jwt-json-web-tokens-4b1871efd
The code is available here: https://github.com/renatogroffe/ASPNETCore2_JWT/tree/master/APIAlturas
I was able to test this project, it works fine with the JWT Bearer Authentication.
The problem began when I had to do some dependency injection in my controllers to retrieve data from my repository. My API was not resolving my dependencies, so I had to make some changes in my Startup.cs file.
Therefore, the only thing that is different now in my project from the example above is the Startup.cs file.
What happens here is that my API generates a token, and when I try to send it to my other controller (in the header) it returns: "Bearer error="invalid_token", error_description="The signature is invalid"
My guess is that something in my Startup.cs file is messing with my authentication.
Here is another thing that I noticed, I set my token configurations in the appsettings.json file. When I call my method that generates my token, those parameters are not set in my tokenConfigurations object. However, debugging the code, my startup.cs file receives the parameters. When I call the controller, these parameters now are null in this object.
public object Post([FromBody]User usuario,[FromServices]SigningConfigurations signingConfigurations, [FromServices]TokenConfigurations tokenConfigurations){ ... my code
}
here is my startup.cs file
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Stratec.WebAPI;
using Stratec.Configuration;
using Stratec.Domain;
using Autofac;
using Hangfire;
using Microsoft.AspNetCore.Http;
using Stratec.Web;
using Hangfire.SqlServer;
namespace Stratec.WebAPI
{
public class Startup
{
public IConfiguration Configuration { get; }
public Startup(IHostingEnvironment env)
{
Configuration = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
// .AddXmlFile("appsettings.xml", optional: true, reloadOnChange: true)
//.AddXmlFile($"appsettings.{env.EnvironmentName}.xml", optional: true)
.AddEnvironmentVariables()
.Build();
Configuracao.Configuration = Configuration;
}
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddTransient<UsersDAO>();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
var signingConfigurations = new SigningConfigurations();
services.AddSingleton(signingConfigurations);
var tokenConfigurations = new TokenConfigurations();
new ConfigureFromConfigurationOptions<TokenConfigurations>(
Configuration.GetSection("TokenConfigurations"))
.Configure(tokenConfigurations);
services.AddSingleton(tokenConfigurations);
services.AddAuthentication(authOptions =>
{
authOptions.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
authOptions.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(bearerOptions =>
{
var paramsValidation = bearerOptions.TokenValidationParameters;
paramsValidation.IssuerSigningKey = signingConfigurations.Key;
paramsValidation.ValidAudience = tokenConfigurations.Audience;
paramsValidation.ValidIssuer = tokenConfigurations.Issuer;
// Valida a assinatura de um token recebido
paramsValidation.ValidateIssuerSigningKey = true;
// Verifica se um token recebido ainda é válido
paramsValidation.ValidateLifetime = true;
// Tempo de tolerância para a expiração de um token (utilizado
// caso haja problemas de sincronismo de horário entre diferentes
// computadores envolvidos no processo de comunicação)
paramsValidation.ClockSkew = TimeSpan.Zero;
});
// Ativa o uso do token como forma de autorizar o acesso
// a recursos deste projeto
services.AddAuthorization(auth =>
{
auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser().Build());
});
services.AddHangfire(x => x.UseSqlServerStorage(Configuration.GetConnectionString("ConexaoPadrao")));
JobStorage.Current = new SqlServerStorage(Configuration.GetConnectionString("ConexaoPadrao"));
// services.AddMvcCore();
services.AddMvc();
var assemblies = new[]
{
typeof(Startup).Assembly,
typeof(Colaborador).Assembly
};
//IContainer container = null;
var serviceProvider = ConfigurationApplication.Inicialize(services, Configuration, assemblies);
//GlobalConfiguration.Configuration.UseAutofacActivator(container);
return serviceProvider;
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMiddleware<UnitOfWorkMiddleware>();
app.UseMiddleware<AutenticacaoMiddleware<Autenticacao>>();
app.UseMvc();
app.UseStaticFiles();
}
}
}
Can somebody help me? I've been trying to find something in the questions here, but I can't find a similar issue.
IServiceProvider
, figure out how to load your other dependencies within theConfigureServices
method declared void. I assume yourConfigurationApplication.Inicialize()
is where this is done? A static call to load dependencies has a certain smell about it. Could be nicely cleaned up using extension methods that returns theIServiceCollection
, not a builtIServiceProvider
. – BradConfigureServices
as void I get the message Unable to resolveUnitOfWorkManager
. I tried something that seemed obviousservices.addScope<UnitOfWorkManager>();
but still I get the same error when calling any method in my controller. Now... There's one more thing, when I return IServiceProvider, the dependencies get resolved, but I get nothing from[fromservices]
in my controller. Is there a way to look what is available from services? – Arthur MedeirosConfigurationApplication.Inicialize
method. Inside of it the code is declaring aContainerBuilder
that does stuff likebuilder.Populate(services);
Then it returns a IContainer. – Arthur Medeiros