Following many tutorials, examples, this example below I call on the server side, but the client side does not receive, sometimes it works but sometimes it doesn’t (more doesn’t work than it works)
It was supposed to be very simple, but it's not, any suggest will help me so much!
Server side
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers().AddNewtonsoftJson(options =>
{
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
var connection = #"data source=comandai.database.windows.net;initial catalog=HojeTaPago;persist security info=True;user id=Comandai;password=Ck#21112009;MultipleActiveResultSets=True;";
services.AddDbContext<ComandaiContext>(options => options.UseSqlServer(connection));
services.AddSignalR(options => options.KeepAliveInterval = TimeSpan.FromSeconds(5));
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddResponseCompression(opts =>
{
opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
new[] { "application/octet-stream" });
});
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "HojeTaPago API", Version = "v1" });
c.AddSecurityDefinition("basic", new OpenApiSecurityScheme
{
Name = "Authorization",
Type = SecuritySchemeType.Http,
Scheme = "basic",
In = ParameterLocation.Header,
Description = "Basic Authorization header using the Bearer scheme."
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "basic"
}
},
new string[] {}
}
});
});
services.AddCors(options => options.AddPolicy("CorsPolicy",
builder =>
{
builder.AllowAnyMethod().AllowAnyHeader()
.AllowCredentials();
}));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseResponseCompression();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "HojeTaPago API V1");
c.RoutePrefix = string.Empty;
});
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors("CorsPolicy");
app.UseAuthentication();
app.UseAuthorization();
app.UseMiddleware<AuthenticationMiddleware>();
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<NovoPedidoHub>("/novopedidohub");
endpoints.MapControllers();
});
}
}
Where im using the signalr
await _novoPedidoContext.Clients.All.SendAsync("NovoPedido", ListaComandaItem);
Client side - Blazor
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddBlazoredLocalStorage();
services.AddBootstrapCss();
services.AddTransient<HubConnectionBuilder>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
}
Where i call..
protected override async Task OnInitializedAsync()
{
DataService dataService = new DataService();
PedidosParaAceitar = new List<Comanda>(await dataService.BuscarComandasAbertas());
connection = _hubConnectionBuilder.WithUrl(dataService.servidor + "novopedidohub",
opt =>
{
opt.Transports = HttpTransportType.WebSockets;
opt.SkipNegotiation = true;
}).Build();
connection.On<List<ComandaItem>>("NovoPedido", async lista =>
{
var idEstabelecimento = await localStorage.GetItemAsync<int>("IdEstabelecimento");
if (lista.FirstOrDefault().Comanda.IdEstabelecimento == idEstabelecimento)
{
if (PedidosParaAceitar == null)
PedidosParaAceitar = new List<Comanda>();
if (PedidosParaAceitar.Count(x => x.Id == lista.FirstOrDefault().IdComanda) > 0)
foreach (var comandaitem in lista)
{
PedidosParaAceitar.FirstOrDefault(x => x.Id == lista.FirstOrDefault().IdComanda).ComandaItem.Add(comandaitem);
}
else
PedidosParaAceitar.Add(await dataService.BuscarComandaAberta(lista.FirstOrDefault().IdComanda));
StateHasChanged();
}
});
await connection.StartAsync();
}
You didn't specify in the tags if this was client-side (WASM) or server-side Blazor.
Looking at the question I noticed this line in ConfigureServices:
services.AddServerSideBlazor();
So you're attempting to use SignalR, a client-side communication library from the Server. In server-side Blazor all the C# code runs on the server. In this respect, SignalR is redundant since it's already being used by Blazor for communicating between the clients and the server.
By a very fortunate coincidence, I actually wrote an app to test this out recently. I created a server-side Blazor app, and wrote this service:
public class TalkService
{
public TalkService()
{
history = new List<string>();
}
public Action<string> OnChange { get; set; }
// inform all users of new message
public Task SendAsync(string message)
{
// add to history
history.Add(message);
// ensure only last 10 shown
if (history.Count > 10) history.RemoveAt(0);
OnChange.Invoke(message);
return Task.FromResult(0);
}
private readonly List<string> history;
public IReadOnlyList<string> GetHistory() => history;
}
I then registered it as a Singleton on the server (all clients use the same service)
in Startup.cs in the ConfigureServices() method:
services.AddSingleton<TalkService>();
Then rewrote Index.razor as follows:
#page "/"
#inject TalkService service
<p>Talk App started</p>
<p>Send a message: <input type="text"#bind="#message" />
<button class="btn btn-sm btn-primary" #onclick="Send" >Send</button>
</p>
#foreach (var m in messages)
{
<p>#m</p>
}
#code {
string message;
async Task Send()
{
if(!string.IsNullOrWhiteSpace(message))
await service.SendAsync(message);
message = string.Empty;
}
List<string> messages;
protected override void OnParametersSet()
{
// load history
messages = service.GetHistory().ToList();
// register for updates
service.OnChange += ChangeHandler;
}
protected void ChangeHandler(string message)
{
messages.Add(message);
InvokeAsync(StateHasChanged);
}
}
The talk service is a basic "chat" example of course. It's a Singleton so all pages/clients that reference it use the same instance. The service has a simple event OnChange that clients (like the Index page) can listen to for changes elsewhere.
SignalR isn't needed for this app since it's already "there" for server-side.
Demo App
The demo app also has a background service that generates time messages as well. I've pushed this to GitHub to help as a guide:
https://github.com/conficient/BlazorServerWithSignalR
I can login and get a jwt
{
"resource": "resource-server",
"token_type": "Bearer",
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI4NzJlMTY5OS0xNGQwLTRhYmItYTU4Mi1kZDZmODkzNWU1NGEiLCJuYW1lIjoidGVzdEB0ZXN0LmNvbSIsInRva2VuX3VzYWdlIjoiYWNjZXNzX3Rva2VuIiwianRpIjoiNzdlMDhiMGMtMGRmMy00NDJjLTgxOTItMDk4YWNiYjdiZWQyIiwiYXVkIjoicmVzb3VyY2Utc2VydmVyIiwibmJmIjoxNDk1NTY0ODI5LCJleHAiOjE0OTU1Njg0MjksImlhdCI6MTQ5NTU2NDgyOSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1NTY2NC8ifQ.00X9de2jtetmWoj4BNaskvtPryElEsenpoVgisCxEoA",
"expires_in": 3600
}
But when I try and get a protected route, I get a 401.
This is my startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Authorization.Data;
using Authorization.Models;
using Authorization.Services;
using OpenIddict.Core;
using OpenIddict.Models;
using AspNet.Security.OpenIdConnect.Primitives;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
namespace Authorization
{
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);
if (env.IsDevelopment())
{
// For more details on using the user secret store see https://go.microsoft.com/fwlink/?LinkID=532709
builder.AddUserSecrets<Startup>();
}
builder.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.AddCors();
// Add framework services.
services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
options.UseOpenIddict();
});
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.Configure<IdentityOptions>(options =>
{
options.ClaimsIdentity.UserNameClaimType = OpenIdConnectConstants.Claims.Name;
options.ClaimsIdentity.UserIdClaimType = OpenIdConnectConstants.Claims.Subject;
options.ClaimsIdentity.RoleClaimType = OpenIdConnectConstants.Claims.Role;
});
var secretKey = "mysupersecret_secretkey!123";
var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey));
services.AddOpenIddict(options =>
{
options.AddEntityFrameworkCoreStores<ApplicationDbContext>();
options.AddMvcBinders();
options.EnableTokenEndpoint("/connect/token");
options.UseJsonWebTokens();
options.AllowPasswordFlow();
options.AddSigningKey(signingKey);
options.DisableHttpsRequirement();
});
services.AddMvc();
// Add application services.
//services.AddTransient<IEmailSender, AuthMessageSender>();
//services.AddTransient<ISmsSender, AuthMessageSender>();
}
// 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();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseCors(builder =>
{
builder.AllowAnyHeader();
builder.AllowAnyMethod();
builder.AllowCredentials();
builder.AllowAnyOrigin(); // For anyone access.
//corsBuilder.WithOrigins("http://localhost:56573"); // for a specific url.
});
app.UseStaticFiles();
//app.UseOAuthValidation();
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
Authority = "http://localhost:55664",
Audience = "resource-server",
AutomaticAuthenticate = true,
AutomaticChallenge = true,
RequireHttpsMetadata = false,
});
app.UseOpenIddict();
// Add external authentication middleware below. To configure them please see https://go.microsoft.com/fwlink/?LinkID=532715
app.UseMvcWithDefaultRoute();
}
}
}
I've tried setting authority and audience to all sorts of different things. I've tried removing them completely and I can not get a 200 back on a route with
[Authorize]
added on.
When I try and do this in Postman, I get the error
Bearer error="invalid_token", error_description="The signature is
invalid"
It's a GET with 1 header, Authorization = bearer {token here}
I'm just at a loss. Been at this for 3 days now. I feel like it's almost right, I'm just missing some key thing. Missing a header or something.
Also note, I have an angular 2 app at localhost:4200. But my understanding is this should still work within postman?
This is the server output when I hit the authorized route
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.2832518Z","tags":{"ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.operation.id":"0HL5214V879CK","ai.application.ver":"1.0.0.0"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Request starting HTTP/1.1 GET http://localhost:55664/api/values","severityLevel":"Information","properties":{"CategoryName":"Microsoft.AspNetCore.Hosting.Internal.WebHost","Protocol":"HTTP/1.1","AspNetCoreEnvironment":"Development","DeveloperMode":"true","Scheme":"http","Host":"localhost:55664","Path":"/api/values","Method":"GET"}}}}
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:55664/api/values
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.2902711Z","tags":{"ai.operation.name":"GET /api/values","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"The request path /api/values does not match a supported file type","severityLevel":"Verbose","properties":{"CategoryName":"Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware","{OriginalFormat}":"The request path {Path} does not match a supported file type","AspNetCoreEnvironment":"Development","DeveloperMode":"true","Path":"/api/values"}}}}
Exception thrown: 'Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException' in System.IdentityModel.Tokens.Jwt.dll
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.3128307Z","tags":{"ai.operation.name":"GET /api/values","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Failed to validate the token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI4NzJlMTY5OS0xNGQwLTRhYmItYTU4Mi1kZDZmODkzNWU1NGEiLCJuYW1lIjoidGVzdEB0ZXN0LmNvbSIsInRva2VuX3VzYWdlIjoiYWNjZXNzX3Rva2VuIiwianRpIjoiNzdlMDhiMGMtMGRmMy00NDJjLTgxOTItMDk4YWNiYjdiZWQyIiwiYXVkIjoicmVzb3VyY2Utc2VydmVyIiwibmJmIjoxNDk1NTY0ODI5LCJleHAiOjE0OTU1Njg0MjksImlhdCI6MTQ5NTU2NDgyOSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1NTY2NC8ifQ.00X9de2jtetmWoj4BNaskvtPryElEsenpoVgisCxEoA.","severityLevel":"Information","properties":{"CategoryName":"Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware","{OriginalFormat}":"Failed to validate the token {Token}.","Token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI4NzJlMTY5OS0xNGQwLTRhYmItYTU4Mi1kZDZmODkzNWU1NGEiLCJuYW1lIjoidGVzdEB0ZXN0LmNvbSIsInRva2VuX3VzYWdlIjoiYWNjZXNzX3Rva2VuIiwianRpIjoiNzdlMDhiMGMtMGRmMy00NDJjLTgxOTItMDk4YWNiYjdiZWQyIiwiYXVkIjoicmVzb3VyY2Utc2VydmVyIiwibmJmIjoxNDk1NTY0ODI5LCJleHAiOjE0OTU1Njg0MjksImlhdCI6MTQ5NTU2NDgyOSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1NTY2NC8ifQ.00X9de2jtetmWoj4BNaskvtPryElEsenpoVgisCxEoA","AspNetCoreEnvironment":"Development","DeveloperMode":"true","Exception":"Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException: IDX10500: Signature validation failed. No security keys were provided to validate the signature.\r\n at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)\r\n at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)\r\n at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.<HandleAuthenticateAsync>d__1.MoveNext()"}}}}
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware:Information: Failed to validate the token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI4NzJlMTY5OS0xNGQwLTRhYmItYTU4Mi1kZDZmODkzNWU1NGEiLCJuYW1lIjoidGVzdEB0ZXN0LmNvbSIsInRva2VuX3VzYWdlIjoiYWNjZXNzX3Rva2VuIiwianRpIjoiNzdlMDhiMGMtMGRmMy00NDJjLTgxOTItMDk4YWNiYjdiZWQyIiwiYXVkIjoicmVzb3VyY2Utc2VydmVyIiwibmJmIjoxNDk1NTY0ODI5LCJleHAiOjE0OTU1Njg0MjksImlhdCI6MTQ5NTU2NDgyOSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1NTY2NC8ifQ.00X9de2jtetmWoj4BNaskvtPryElEsenpoVgisCxEoA.
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException: IDX10500: Signature validation failed. No security keys were provided to validate the signature.
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.<HandleAuthenticateAsync>d__1.MoveNext()
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.3173431Z","tags":{"ai.operation.name":"GET /api/values","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Bearer was not authenticated. Failure message: IDX10500: Signature validation failed. No security keys were provided to validate the signature.","severityLevel":"Information","properties":{"FailureMessage":"IDX10500: Signature validation failed. No security keys were provided to validate the signature.","CategoryName":"Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware","AuthenticationScheme":"Bearer","{OriginalFormat}":"{AuthenticationScheme} was not authenticated. Failure message: {FailureMessage}","AspNetCoreEnvironment":"Development","DeveloperMode":"true"}}}}
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware:Information: Bearer was not authenticated. Failure message: IDX10500: Signature validation failed. No security keys were provided to validate the signature.
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.3238602Z","tags":{"ai.operation.name":"GET /api/values","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Request successfully matched the route with name '(null)' and template 'api/Values'.","severityLevel":"Verbose","properties":{"CategoryName":"Microsoft.AspNetCore.Routing.Tree.TreeRouter","{OriginalFormat}":"Request successfully matched the route with name '{RouteName}' and template '{RouteTemplate}'.","AspNetCoreEnvironment":"Development","DeveloperMode":"true","RouteTemplate":"api/Values"}}}}
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.3253638Z","tags":{"ai.operation.name":"GET /api/values","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Action 'AspToken.Controllers.ValuesController.Post (Authorization)' with id 'd8fd53b2-6692-4c31-b8ce-0d7965e7e5b1' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint'","severityLevel":"Verbose","properties":{"CategoryName":"Microsoft.AspNetCore.Mvc.Internal.ActionSelector","{OriginalFormat}":"Action '{ActionName}' with id '{ActionId}' did not match the constraint '{ActionConstraint}'","AspNetCoreEnvironment":"Development","ActionConstraint":"Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint","ActionId":"d8fd53b2-6692-4c31-b8ce-0d7965e7e5b1","DeveloperMode":"true","ActionName":"AspToken.Controllers.ValuesController.Post (Authorization)"}}}}
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.3273695Z","tags":{"ai.operation.name":"GET Values/Get","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Executing action AspToken.Controllers.ValuesController.Get (Authorization)","severityLevel":"Verbose","properties":{"CategoryName":"Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker","{OriginalFormat}":"Executing action {ActionName}","AspNetCoreEnvironment":"Development","DeveloperMode":"true","ActionName":"AspToken.Controllers.ValuesController.Get (Authorization)"}}}}
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.3293745Z","tags":{"ai.operation.name":"GET Values/Get","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Authorization failed for user: (null).","severityLevel":"Information","properties":{"CategoryName":"Microsoft.AspNetCore.Authorization.DefaultAuthorizationService","{OriginalFormat}":"Authorization failed for user: {UserName}.","AspNetCoreEnvironment":"Development","DeveloperMode":"true"}}}}
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization failed for user: (null).
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.3323827Z","tags":{"ai.operation.name":"GET Values/Get","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.","severityLevel":"Information","properties":{"CategoryName":"Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker","{OriginalFormat}":"Authorization failed for the request at filter '{AuthorizationFilter}'.","AuthorizationFilter":"Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter","AspNetCoreEnvironment":"Development","DeveloperMode":"true"}}}}
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.3348898Z","tags":{"ai.operation.name":"GET Values/Get","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Executing ChallengeResult with authentication schemes ().","severityLevel":"Information","properties":{"CategoryName":"Microsoft.AspNetCore.Mvc.ChallengeResult","{OriginalFormat}":"Executing ChallengeResult with authentication schemes ({Schemes}).","AspNetCoreEnvironment":"Development","DeveloperMode":"true","Schemes":"System.String[]"}}}}
Microsoft.AspNetCore.Mvc.ChallengeResult:Information: Executing ChallengeResult with authentication schemes ().
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.3378977Z","tags":{"ai.operation.name":"GET Values/Get","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"AuthenticationScheme: Bearer was challenged.","severityLevel":"Information","properties":{"CategoryName":"Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware","AuthenticationScheme":"Bearer","{OriginalFormat}":"AuthenticationScheme: {AuthenticationScheme} was challenged.","AspNetCoreEnvironment":"Development","DeveloperMode":"true"}}}}
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware:Information: AuthenticationScheme: Bearer was challenged.
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.3409055Z","tags":{"ai.operation.name":"GET Values/Get","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Executed action AspToken.Controllers.ValuesController.Get (Authorization) in 11.408ms","severityLevel":"Information","properties":{"CategoryName":"Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker","ElapsedMilliseconds":"11.408","{OriginalFormat}":"Executed action {ActionName} in {ElapsedMilliseconds}ms","AspNetCoreEnvironment":"Development","DeveloperMode":"true","ActionName":"AspToken.Controllers.ValuesController.Get (Authorization)"}}}}
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action AspToken.Controllers.ValuesController.Get (Authorization) in 11.408ms
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.3439137Z","tags":{"ai.operation.name":"GET Values/Get","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Connection id \"0HL5214V6KQ2K\" completed keep alive response.","severityLevel":"Verbose","properties":{"CategoryName":"Microsoft.AspNetCore.Server.Kestrel","{OriginalFormat}":"Connection id \"{ConnectionId}\" completed keep alive response.","AspNetCoreEnvironment":"Development","DeveloperMode":"true","ConnectionId":"0HL5214V6KQ2K"}}}}
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.3454177Z","tags":{"ai.operation.name":"GET Values/Get","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Request finished in 61.7295ms 401","severityLevel":"Information","properties":{"CategoryName":"Microsoft.AspNetCore.Hosting.Internal.WebHost","ElapsedMilliseconds":"61.7295","StatusCode":"401","AspNetCoreEnvironment":"Development","DeveloperMode":"true"}}}}
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 61.7295ms 401
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Request","time":"2017-05-23T18:49:45.3318446Z","tags":{"ai.operation.name":"GET Values/Get","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"RequestData","baseData":{"ver":2,"id":"5sE5TCp7osw=","name":"GET Values/Get","duration":"00:00:00.0180848","success":false,"responseCode":"401","url":"http://localhost:55664/api/values","properties":{"httpMethod":"GET","AspNetCoreEnvironment":"Development","DeveloperMode":"true"}}}}
Sigh. I'm an idiot.
If you sign your key
options.AddSigningKey(signingKey);
Then you need to tell the
app.UseJwtBearerAuthentication
how to validate that key.
TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = signingKey,
ValidateIssuer = true,
ValidateAudience = true,
ValidAudience = audience,
ValidateLifetime = true,
}
My complete startup file for anyone that also gets stuck on this.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Authorization.Data;
using Authorization.Models;
using Authorization.Services;
using OpenIddict.Core;
using OpenIddict.Models;
using AspNet.Security.OpenIdConnect.Primitives;
using Microsoft.IdentityModel.Tokens;
using System.Text;
namespace Authorization
{
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);
if (env.IsDevelopment())
{
// For more details on using the user secret store see https://go.microsoft.com/fwlink/?LinkID=532709
builder.AddUserSecrets<Startup>();
}
builder.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.AddCors();
// Add framework services.
services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
options.UseOpenIddict();
});
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.Configure<IdentityOptions>(options =>
{
options.ClaimsIdentity.UserNameClaimType = OpenIdConnectConstants.Claims.Name;
options.ClaimsIdentity.UserIdClaimType = OpenIdConnectConstants.Claims.Subject;
options.ClaimsIdentity.RoleClaimType = OpenIdConnectConstants.Claims.Role;
});
var secretKey = "mysupersecret_secretkey!123";
var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey));
services.AddOpenIddict(options =>
{
options.AddEntityFrameworkCoreStores<ApplicationDbContext>();
options.AddMvcBinders();
options.EnableTokenEndpoint("/connect/token");
options.UseJsonWebTokens();
options.AllowPasswordFlow();
options.AddSigningKey(signingKey);
options.DisableHttpsRequirement();
});
services.AddMvc();
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
}
// 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();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseCors(builder =>
{
builder.AllowAnyHeader();
builder.AllowAnyMethod();
builder.AllowCredentials();
builder.AllowAnyOrigin(); // For anyone access.
//corsBuilder.WithOrigins("http://localhost:56573"); // for a specific url.
});
app.UseStaticFiles();
var audience = "resource-server";
var authority = "http://localhost:55664";
var secretKey = "mysupersecret_secretkey!123";
var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey));
//app.UseOAuthValidation();
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
Authority = authority,
Audience = audience,
AutomaticAuthenticate = true,
AutomaticChallenge = true,
RequireHttpsMetadata = false,
TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = signingKey,
ValidateIssuer = true,
// makes no difference seemingly being ignored
//ValidIssuer = Configuration.Get<AppOptions>().Jwt.Authority,
ValidateAudience = true,
ValidAudience = audience,
ValidateLifetime = true,
}
});
app.UseOpenIddict();
// Add external authentication middleware below. To configure them please see https://go.microsoft.com/fwlink/?LinkID=532715
app.UseMvcWithDefaultRoute();
}
}
}
I updated ASP.NET 5 framework beta-8 packages with RC ones on previously working application. After I got it running next error occured in the startup process:
InvalidOperationException: No authentication handler is configured to handle the scheme: Automatic
Microsoft.AspNet.Http.Authentication.Internal.DefaultAuthenticationManager.d__12.MoveNext()
var defaultPolicy =
new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
services.AddMvc(setup =>
{
setup.Filters.Add(new AuthorizeFilter(defaultPolicy)); // Error occurs here
});
If anyone had similar problem, I'd appreciate your idea or solution on what might have gone wrong. Explanation of this exception is also appreciated.
Startup.cs
using Autofac;
using Autofac.Extensions.DependencyInjection;
using Microsoft.AspNet.Authorization;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.PlatformAbstractions;
using SuperUserMVC.Configuration;
using SuperUserMVC.Extensions;
using SuperUserMVC.GlobalModules;
using System;
namespace SuperUserMVC
{
public class Startup
{
public IConfigurationRoot Configuration { get; set; }
// Entry point for the application.
public static void Main(string[] args) => WebApplication.Run<Startup>(args);
public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
{
var builder = new ConfigurationBuilder()
.SetBasePath(appEnv.ApplicationBasePath)
.AddJsonFile("appsettings.json");
Configuration = builder.Build();
}
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.Configure<AppSettingsBase>(Configuration.GetSection("AppSettingsBase"));
services.Configure<ConnectionString>(Configuration.GetSection("ConnectionString"));
services.AddSqlServerCache(cache =>
{
cache.ConnectionString = Configuration.Get<string>("ASPState:ConnectionString");
cache.SchemaName = Configuration.Get<string>("ASPState:Schema");
cache.TableName = Configuration.Get<string>("ASPState:Table");
});
services.AddSession(session =>
{
session.IdleTimeout = TimeSpan.FromMinutes(120);
});
// Only allow authenticated users.
var defaultPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
// Add MVC services to the services container.
services.AddMvc(setup =>
{
setup.Filters.Add(new AuthorizeFilter(defaultPolicy));
});
var builder = new ContainerBuilder();
builder.RegisterModule(new AutofacModule());
builder.Populate(services);
var container = builder.Build();
return container.Resolve<IServiceProvider>();
}
public void Configure(IApplicationBuilder app, IHttpContextAccessor httpContextAccessor)
{
// Catch unhandled exception in pipeline.
bool isProductionEnvironment = Configuration.Get<bool>("environmentVariables:isProductionEnvironment");
app.UseCustomUnhandledException(isProductionEnvironment, Configuration.Get<string>("defaultErrorPagePath"));
// Log requests.
app.UseVisitLogger(isProductionEnvironment);
// Session must be used before MVC routes.
app.UseSession();
// Configure the HTTP request pipeline.
app.UseCookieAuthentication(options =>
{
options.AuthenticationScheme = "Cookies";
options.LoginPath = new PathString("/Account/Login/");
options.AccessDeniedPath = new PathString("/Account/Forbidden/");
options.CookieName = "MyCookie";
options.AutomaticAuthenticate = true;
options.SessionStore = new MemoryCacheSessionStore();
});
AutoMapperInitializer.Init();
app.UseStaticFiles();
// Route configuration.
app.UseMvc(routes =>
{
routes.MapRoute(
name: "AreaDefault",
template: "{area:exists=Demo}/{controller=Home}/{action=Index}/{id?}"
);
routes.MapRoute(
name: "Default",
template: "{controller=Home}/{action=Index}/{id?}"
);
});
}
}
}
Hopefully this will help somebody else because I just spent a lot of time dealing with this error even though I had set AutomaticChallenge = true.
Turns out you will get the same error if you put app.UseIdentity(); after app.UseMvc(routes => ...). Now that I know the answer it's obvious. It's because all this middleware happens in the order you add it.
This causes the "No authentication handler is configured" error:
public void Configure(...)
{
app.UseMvc(routes => { routes.MapRoute(...) }; );
app.UseIdentity();
}
This does not cause the error:
public void Configure(...)
{
app.UseIdentity();
app.UseMvc(routes => { routes.MapRoute(...); });
}
Try setting options.AutomaticChallenge = true; in your cookies options and it should work.
options.AutomaticAuthentication was split into options.AutomaticAuthenticate and options.AutomaticChallenge. If the last one is left to false, an exception is thrown because no authentication middleware handles the challenge applied by the authorization filter.
Put this on Configure method.
app.UseIdentity();
The problem was solved for me by making sure the cookies scheme was consistently named wherever it was referenced. e.g.:
public void ConfigureServices(IServiceCollection services)
{
// if using IdentityServer4
var builder = services.AddIdentityServer(options =>
{
options.AuthenticationOptions.AuthenticationScheme = Constants.DefaultCookieAuthenticationScheme;
...
})
services.AddIdentity<MyUser, IdentityRole>(options =>
{
options.Cookies.ApplicationCookie.AuthenticationScheme = Constants.DefaultCookieAuthenticationScheme;
...
}
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
...
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationScheme = Constants.DefaultCookieAuthenticationScheme,
AutomaticAuthenticate = false,
AutomaticChallenge = true
});
}
And when interacting with the authentication middleware. e.g.:
await HttpContext.Authentication.SignInAsync(Constants.DefaultCookieAuthenticationScheme, cp);
If you use app.UseIdentity(); and some other login middleware such as UseFacebookAuthentication make sure app.UseFacebookAuthentication() is AFTER app.UseIdentity();.
another possibility is missing the following setting in Configure
app.UseCookieAuthentication();
While it's tempting to place much of our configuration settings within the startup.cs file, it seems that the preferred way of doing things is to set your app.UseCookieAuthentication() - sans options - within the startup.cs file, and then place all of the 'options' and other details within a separate file.
Sort of like what we were doing with how the Global.asax file had pointers to the App_Start folder files in Asp.Net vBefore.
I suffered similar pain while trying to configure EF/Sql in the startup.cs, and by moving all 'options' outside of startup.cs things worked much better.
ALSO: take note of the Fredy Wenger comment to your question that points out the 'renaming' of many of the namespaces from v -8beta to v -RC1-final.