I follow the tutorial link below.
https://fullstackmark.com/post/13/jwt-authentication-with-aspnet-core-2-web-api-angular-5-net-core-identity-and-facebook-login
I am trying to understand how it works and I want to use role-based authentication using this token. so I made another policy in the Startup.cs file as below.
And I tried to use it like [Authorize(Policy = "admin")] the controller but every time I try I get unauthenticated using postman.
What am I missing? how to make roles-based authentication based on the tutorial?
Configure
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.WithOrigins("http://localhost:4200", "http://localhost:44318")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
var jwtAppSettingOptions = Configuration.GetSection(nameof(JwtIssuerOptions));
// Configure JwtIssuerOptions
services.Configure<JwtIssuerOptions>(options =>
{
options.Issuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
options.Audience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)];
options.SigningCredentials = new SigningCredentials(_signingKey, SecurityAlgorithms.HmacSha256);
});
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)],
ValidateAudience = true,
ValidAudience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)],
ValidateIssuerSigningKey = true,
IssuerSigningKey = _signingKey,
RequireExpirationTime = false,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(configureOptions =>
{
configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
configureOptions.TokenValidationParameters = tokenValidationParameters;
configureOptions.SaveToken = true;
});
// api user claim policy
services.AddAuthorization(options =>
{
options.AddPolicy("ApiUser", policy => policy.RequireClaim(Constants.Strings.JwtClaimIdentifiers.Rol, Constants.Strings.JwtClaims.ApiAccess));
});
services.AddAuthorization(options =>
options.AddPolicy("admin", policy => policy.RequireRole("admin"))
);
var builder = services.AddIdentityCore<AppUser>(o =>
{
// configure identity options
o.Password.RequireDigit = false;
o.Password.RequireLowercase = false;
o.Password.RequireUppercase = false;
o.Password.RequireNonAlphanumeric = false;
o.Password.RequiredLength = 6;
});
builder = new IdentityBuilder(builder.UserType, typeof(IdentityRole), builder.Services);
builder.AddEntityFrameworkStores<CDSPORTALContext>().AddDefaultTokenProviders().AddRoles<IdentityRole>();
//.AddRoles<IdentityRole>()
services.AddControllers();
services.AddAutoMapper(typeof(Startup));
services.AddSingleton<IJwtFactory, JwtFactory>();
services.TryAddTransient<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<IRegionRepository, RegionRepository>();
services.AddScoped<IRegionService, RegionService>();
services.AddScoped<IEmailHelper, EmailHelper>();
}
// 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("/Home/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.UseCors("CorsPolicy");
app.UseExceptionHandler(
builder =>
{
builder.Run(
async context =>
{
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
var error = context.Features.Get<IExceptionHandlerFeature>();
if (error != null)
{
context.Response.AddApplicationError(error.Error.Message);
await context.Response.WriteAsync(error.Error.Message).ConfigureAwait(false);
}
});
});
app.UseRouting();
app.UseStaticFiles();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "Client";
spa.UseAngularCliServer(npmScript: "start");
});
}
}
Auth Controller
// POST api/auth/login
[HttpPost("login")]
public async Task<IActionResult> Post([FromBody]CredentialsViewModel credentials)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var identity = await GetClaimsIdentity(credentials.UserName, credentials.Password);
if (identity == null)
{
//return null;
return BadRequest(Error.AddErrorToModelState("login_failure", "Invalid username or password.", ModelState));
}
var id = identity.Claims.Single(c => c.Type == "id").Value;
var user = await _userManager.FindByIdAsync(id);
IList<string> role = await _userManager.GetRolesAsync(user);
var jwt = await Tokens.GenerateJwt(identity, role[0], _jwtFactory, credentials.UserName, _jwtOptions, new JsonSerializerSettings { Formatting = Formatting.Indented });
return new OkObjectResult(jwt);
}
I tried with all method and none of them working
[Authorize(Policy = "ApiUser")]
[HttpGet("getPolicy")]
public string GetPolicy()
{
return "policyWorking";
}
[Authorize(Roles = "admin")]
[HttpGet("getAdmin")]
public string GetAdmin()
{
return "adminWorking";
}
[Authorize ]
[HttpGet("getAuthorize")]
public string GetAuthorize()
{
return "normal authorize Working";
}
Decoded Token
"jti": "840d507d-b2d0-454b-bd1f-007890d3e669",
"iat": 1587699300,
"rol": "api_access",
"id": "1ac370e2-f5e9-4404-b017-8a3c087e2196",
"nbf": 1587699299,
"exp": 1587706499
I forgot to add this to appsetting.
"JwtIssuerOptions": {
"Issuer": "webApi",
"Audience": "http://localhost:4200/"
}
Related
post request
{
"FullName":"123",
"Password":"123"
}
Here is the postman error.
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-c6c66dedbd981c409a0b5011bfc83ca7-0c6499593cff6f4b-00",
"errors": {
"ControllerContext.RouteData": [
"The RouteData field is required."
],
"ControllerContext.HttpContext": [
"The HttpContext field is required."
]
}
}
'''
My project was crushed and I rewrite it. My Database is already the past one. And I made the migration and update the database. When I was trying to log in with exists user I can. But when I try to register using angular or postman it gives an error. I can not handle the problem and I searched then I got nothing to do.
here my register method:
public async Task<Object> PostUser(UserModel model)
{
var user = new User()
{
FullName = model.FullName,
};
try
{
var result = await _userManager.CreateAsync(user, model.Password);
return Ok(result);
}
catch (Exception ex)
{
throw ex;
}
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddCors(o => o.AddPolicy("AllowAnyCorsPolicy", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
}));
//D.injection
services.Configure<ApplicationSettings>(Configuration.GetSection("ApplicationSettings"));
services.AddDbContext<AuthenticationContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("IdentityConnection")));
services.AddIdentity<User, IdentityRole>().AddEntityFrameworkStores<AuthenticationContext>();
services.Configure<IdentityOptions>(options =>
{
options.Password.RequireDigit = false;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireLowercase = false;
options.Password.RequireUppercase = false;
options.Password.RequiredLength = 4;
});
//JWT Auth
var key = Encoding.UTF8.GetBytes(Configuration["ApplicationSettings:JWT_Secret"].ToString());
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = false,
};
});
}
// 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");
}
app.UseStaticFiles();
app.UseRouting();
app.UseCors(builder =>
builder.WithOrigins(Configuration["ApplicationSettings:Client_URL"].ToString())
.AllowAnyHeader()
.AllowAnyMethod()
);
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
});
}
I'm trying to implement authorization in asp.ne core webapi web application using jwt tokens.
but when I send a request with bearer authorization and the jwt token generated, the response is always 401 unauthorized
I'm using .Net 5.0 version
what I'm doing wrong ?
here is my startup.cs file
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.Configure<JwtSettings>(Configuration.GetSection("Jwt"));
var jwtSettings = Configuration.GetSection("Jwt").Get<JwtSettings>();
services.AddControllers();
var dataAssemblyName = typeof(CRMContext).Assembly.GetName().Name;
services.AddDbContext<CRMContext>(options => options.UseSqlServer(Configuration.GetConnectionString("Default"), x => x.MigrationsAssembly(dataAssemblyName)));
services.AddIdentity<User, Role>(options =>
{
options.Password.RequiredLength = 8;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = true;
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(1d);
options.Lockout.MaxFailedAccessAttempts = 5;
})
.AddEntityFrameworkStores<CRMContext>()
.AddDefaultTokenProviders();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["JwtAuthentication:JwtIssuer"],
ValidAudience = Configuration["JwtAuthentication:JwtIssuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JwtAuthentication:JwtKey"])),
};
});
services.AddScoped<IUnitOfWork, UnitOfWork>();
services.AddTransient<IAccountService, AccountService>();
services.AddTransient<IApplicationUserService, ApplicationUserService>();
services.AddMvc().AddControllersAsServices();
services.AddCors(o => o.AddPolicy("MyPolicy", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
}));
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo { Title = "Cloud 9", Version = "v1" });
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "JWT containing userid claim",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
});
var security =
new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Id = "Bearer",
Type = ReferenceType.SecurityScheme
},
UnresolvedReference = true
},
new List<string>()
}
};
options.AddSecurityRequirement(security);
});
services.AddAutoMapper(typeof(Startup));
services.AddControllersWithViews()
.AddNewtonsoftJson(options =>
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);
var mappingConfig = new MapperConfiguration(mc =>
{
mc.AddProfile(new MappingProfile());
});
IMapper mapper = mappingConfig.CreateMapper();
services.AddSingleton(mapper);
services.AddAuth(jwtSettings);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
MyServiceProvider.ServiceProvider = app.ApplicationServices;
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
// app.UseSwagger();
// app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Ids.Crm.Api v1"));
app.UseAuthorization();
app.UseAuth();
app.UseCors("MyPolicy");
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseSwagger()
.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "test v1");
c.ConfigObject.AdditionalItems.Add("syntaxHighlight", false);
c.ConfigObject.AdditionalItems.Add("theme", "agate");
});
}
Your request pipeline is missing the authentication middleware. So you couldn't possibly authenticate or possibly authorize. Simply add the middleware before the authorization middleware in the Configure method
app.UseAuthentication();
app.UseAuthorization();
Update: It seems app.UseAuth(); is your authentication middleware. If it is, then place it above the Authorization middleware.
app.UseAuth();
app.UseAuthorization();
I found the solution.... I was declaring a key in the generation of the token which is different from the one I've declared in the appsetting.json
so when the TokenValidationParameters takes the wrong key it was preventing authorization
public class User: IdentityUser
{
// ... code here
}
[HttpPost]
[Route("Login")]
//POST: /api/User/Login
public async Task<IActionResult> Login(LoginModel model)
{
var user = await _UserManager.FindByEmailAsync(model.Email);
if (user != null && await _UserManager.CheckPasswordAsync(user, model.Password))
{
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(
new Claim[]
{
new Claim("UserID", user.Id.ToString())
}),
Expires = DateTime.UtcNow.AddDays(5),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_ApplicationSettings.JWT_Secret)), SecurityAlgorithms.HmacSha256Signature)
};
var tokenHandler = new JwtSecurityTokenHandler();
var securityToken = tokenHandler.CreateToken(tokenDescriptor);
var token = tokenHandler.WriteToken(securityToken);
return Ok(new { token });
}
else
{
return BadRequest(new { message = "Username or password is incorrect" });
}
}
}
[HttpGet]
[Authorize]
//GET: /api/UserProfile
public async Task<Object> GetUserProfile()
{
var t = User.Claims.Count();
string userId = User.Claims.First(c => c.Type == "UserID").Value;
var user = await _UserManager.FindByIdAsync(userId);
return new
{
user.FirstName,
user.LastName,
user.Email,
user.ProfileType
};
}
}
When I try to get the connected user with the returned token (using postman), I always get status 401 Unathorized.
Also, i found out that User.Claims.Count() is 0 ( i did this by commenting the in order to see what's wrong [Authorize]).
Does anyone know what the issue is?
Thanks!
EDIT: App configuration
public void ConfigureServices(IServiceCollection services)
{
//Inject AppSettings
services.Configure<ApplicationSettings>(Configuration.GetSection("ApplicationSettings"));
services.AddControllers();
services.AddDbContext<AuthentificationContext>(
options =>
{
options.UseMySql(Configuration.GetConnectionString("IdentityConnection"));
});
services.AddDefaultIdentity<User>()
.AddEntityFrameworkStores<AuthentificationContext>();
services.Configure<IdentityOptions>(options =>
{
options.Password.RequireDigit = false;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireLowercase = false;
options.Password.RequireUppercase = false;
options.Password.RequiredLength = 6;
options.User.RequireUniqueEmail = true;
}
);
services.AddCors();
//jwt authentification
var key = Encoding.UTF8.GetBytes(Configuration["ApplicationSettings:JWT_Secret"].ToString());
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = false;
x.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false,
ClockSkew = TimeSpan.Zero
};
});
services.Configure<CookiePolicyOptions>(options =>
{
services.AddHttpContextAccessor();
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.Use(async (ctx, next) =>
{
await next();
if (ctx.Response.StatusCode == 204)
{
ctx.Response.ContentLength = 0;
}
});
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors(options =>
options.WithOrigins(Configuration["ApplicationSettings:Client_URL"].ToString())
.AllowAnyMethod()
.AllowAnyHeader());
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseAuthentication();
}
}
You should pay attention to the middleware order that put app.UseAuthentication(); before app.UseAuthorization();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
After migrating from .net core 2.2 to .net core 3.1, and after taking some time to fix all the bugs depending on documentations, after running the app, the authorization method get's hit before it requires the user to be authenticated.
I am using OpenId Connect with AD FS for authentication and a custom method called "PermissionGranted" for authorization. And this method get's hit before it requires for the user to be authenticated.
This is the code of my Startup.cs file:
public class Startup
{
private readonly ConfigSettings settings;
private readonly GetSettings configSettings;
private readonly MyMemoryCache myMemoryCache;
public Startup(IWebHostEnvironment env, IConfiguration configuration)
{
configSettings = new GetSettings();
settings = configSettings.getSettings();
Configuration = configuration;
Environment = env;
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
myMemoryCache = new MyMemoryCache();
Log.Logger = new LoggerConfiguration().Enrich.FromLogContext()
.WriteTo.Console()
.WriteTo.File(settings.LogFile, rollingInterval: RollingInterval.Day)
.WriteTo.ApplicationInsights(new TelemetryConfiguration(settings.AppInsightsConnection), TelemetryConverter.Events)
.CreateLogger();
}
public IConfiguration Configuration { get; }
private IWebHostEnvironment Environment { get; }
public IServiceProvider ServiceProvider { get; set; }
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(Log.Logger);
services.AddSingleton(settings);
services.AddHttpContextAccessor();
services.AddRouting(options => options.LowercaseUrls = true);
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => false;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies", options =>
{
options.AccessDeniedPath = "/users/denied";
})
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.MetadataAddress = settings.MetadataAddress;
options.ClientId = settings.ClientId;
options.GetClaimsFromUserInfoEndpoint = true;
options.ResponseType = OpenIdConnectResponseType.IdToken;
options.SignedOutRedirectUri = settings.PostLogoutUri;
options.SaveTokens = true;
options.UseTokenLifetime = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = true,
ValidAudience = settings.ClientId,
ValidateIssuer = true,
ValidIssuer = settings.Issuer,
ValidateLifetime = true,
RequireExpirationTime = true
};
options.Events = new OpenIdConnectEvents
{
OnRemoteFailure = context =>
{
context.HandleResponse();
context.Response.Redirect("/Login");
return Task.FromResult(0);
},
OnTicketReceived = context =>
{
// Configuration to make the Authentication cookie persistent for 8 hours (after 8 hours it expires and the user has to re-authenticate)
context.Properties.IsPersistent = true;
context.Properties.ExpiresUtc = DateTimeOffset.UtcNow.AddHours(8);
return Task.FromResult(0);
}
};
options.Events.OnRedirectToIdentityProvider = context =>
{
context.ProtocolMessage.Prompt = "login";
return Task.CompletedTask;
};
});
Audit.Core.Configuration.Setup()
.UseSqlServer(config => config
.ConnectionString(settings.ConnectionString)
.TableName("AuditEvents")
.IdColumnName("EventId")
.JsonColumnName("AuditData")
.LastUpdatedColumnName("LastUpdatedDate"));
services.AddAntiforgery(options => options.HeaderName = "X-CSRF-TOKEN");
services.AddApplicationInsightsTelemetry(settings.AppInsightsConnection);
services.AddMvc(options =>
{
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
options.Filters.Add(new AuthorizeFilter(policy));
})
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
// Use NewtonsoftJson and custom date format
services.AddControllers().AddNewtonsoftJson(options =>
{
options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
});
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(15);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true; // Make the session cookie essential
});
services.AddAuthorization(options =>
{
options.AddPolicy("Permissions", policy => policy.RequireAssertion(context => PermissionGranted(context)));
});
services.AddDbContext<PasswordManagerContext>(options =>
options.UseSqlServer(settings.ConnectionString));
services.AddSingleton<MyMemoryCache>();
services.AddPaging(options =>
{
options.ViewName = "PagerUI";
options.HtmlIndicatorDown = " <span>↓</span>";
options.HtmlIndicatorUp = " <span>↑</span>";
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IAntiforgery antiforgery)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSession();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Login}/{action=Index}/{id?}");
//endpoints.MapFallbackToController("Index", "Home");
});
ServiceProvider = app.ApplicationServices;
}
According to official docs, the order of these:
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints
matters but in my code they are ordered correctly.
What could be missing or what could possibly be wrong in the configuration?
Thanks in advance
As soon as I connect the SignalR to the application using Install-package Microsoft.AspNetCore.SignalR immediately stops working the POST method of one of the controllers. Without a signal, all works fine. Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options => options.UseMySql(configuration.GetConnectionString("DefaultConnection")));
var section = configuration.GetSection("AppSettings");
var settings = section.Get<AppSettings>();
services.Configure<AppSettings>(section);
var builder = services.AddIdentityCore<ApplicationUser>(user =>
{
user.Password.RequireDigit = true;
user.Password.RequireLowercase = false;
user.Password.RequireUppercase = false;
user.Password.RequireNonAlphanumeric = false;
user.Password.RequiredLength = 6;
});
builder = new IdentityBuilder(builder.UserType, typeof(IdentityRole), builder.Services);
builder.AddSignInManager<SignInManager<ApplicationUser>>();
builder.AddRoleValidator<RoleValidator<IdentityRole>>();
builder.AddRoleManager<RoleManager<IdentityRole>>();
builder.AddEntityFrameworkStores<ApplicationDbContext>();
builder.AddDefaultTokenProviders();
services.AddCors(options => options.AddPolicy("CorsPolicy", policy =>
{
policy
.AllowAnyMethod()
.AllowAnyHeader()
.AllowAnyOrigin()
.AllowCredentials();
}));
services.AddSignalR();
services.AddOData();
services.AddMvc();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = settings.issuer,
ValidAudience = settings.issuer,
IssuerSigningKey = JwtSecurityKey.Create(settings.key)
};
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
if (context.Request.Path.Value.StartsWith("/chatHub") &&
context.Request.Query.TryGetValue("token", out StringValues token)
)
{
context.Token = token;
}
return Task.CompletedTask;
},
OnAuthenticationFailed = context =>
{
Console.WriteLine("OnAuthenticationFailed: " + context.Exception.Message);
return Task.CompletedTask;
},
OnTokenValidated = context =>
{
Console.WriteLine("OnTokenValidated: " + context.SecurityToken);
return Task.CompletedTask;
}
};
});
services.AddAuthorization(options =>
{
options.AddPolicy("user", policy => policy.RequireClaim("id"));
});
services.AddSingleton<ISendGridClient, SendGridClient>(serviceProvider =>
{
return new SendGridClient(settings.sendGridKey);
});
services.AddSingleton<ILogger>(serviceProvider =>
{
return loggerFactory.CreateLogger("logger");
});
services.AddSingleton<IEmailSender, EmailSender>();
services.AddSingleton<IUploader, Uploader>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseAuthentication();
app.UseCors("CorsPolicy");
app.UseSignalR(routes =>
{
routes.MapHub<SignalRHub>("/chatHub");
});
app.UseMvc(routebuilder =>
{
routebuilder.MapRoute(name: "DefaultApi", template: "api/{controller=Home}/{action=Index}/{id?}");
});
}
Controller:
[Authorize(Policy = "user")]
public class UserFilesController : Controller
{
[HttpPost]
public async Task<IActionResult> SaveAvatar(AvatarModel avatar)
{
// Some code here, here the call does not even come
}
}
Calling in JavaScript
$.ajax({
method: 'POST',
url: serviceUrl + 'api/userfiles/saveavatar',
data: data,
headers: getHeaders()
}).done(function (UploadResult) {
// some code here
});