As title says, I want to implement some kind of authorization in .NET Core 2.1, but I have a trouble following their tutorials. I have set up the Startup.cs file
public void ConfigureServices(IServiceCollection services)
{
string connection = Configuration.GetConnectionString("DefaultConnection");
if (_currentEnvironment.IsDevelopment())
services.AddDbContext<PagesContext>(options => options.UseSqlServer(connection), ServiceLifetime.Singleton);
else
services.AddDbContext<PagesContext>(options => options.UseMySql(connection), ServiceLifetime.Singleton);
services.AddIdentity<User, IdentityRole>(opts=>
{
opts.Password.RequireDigit = false;
opts.Password.RequiredLength = 8;
opts.Password.RequireLowercase = false;
opts.Password.RequireNonAlphanumeric = false;
opts.Password.RequireUppercase = false;
opts.User.AllowedUserNameCharacters = null;
}).AddEntityFrameworkStores<PagesContext>()
.AddDefaultTokenProviders();
services.AddSingleton<IStringLocalizerFactory, EFStringLocalizerFactory>();
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseStatusCodePages();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
var supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("en-GB"),
new CultureInfo("en"),
new CultureInfo("ru-RU"),
new CultureInfo("ru"),
new CultureInfo("uk-UA"),
new CultureInfo("ua")
};
app.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("ru-RU"),
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures
});
app.UseStaticFiles();
app.UseAuthentication();
app.UseMvc(
routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
}
);
And I have the HomeController.cs file with following contents:
[HttpGet]
public async Task<IActionResult> Index()
{
var user = await _userManager.GetUserAsync(HttpContext.User);
if (user != null)
{
if (await _userManager.IsInRoleAsync(user, "Admin"))
{
return LocalRedirectPermanent("/Admin/Index");
}
else if (await _userManager.IsInRoleAsync(user, "Carrier"))
{
return LocalRedirectPermanent("/Carrier/Index");
}
return LocalRedirectPermanent("/Passenger/Index");
}
Page indexPage = db.Page.Include(u => u.Title).Include(u => u.Description).FirstOrDefault(p => p.Tag == "main_page");
return View();
}
As it can be seen from the code I want to detect, if user is logged in - to show the corresponding page. If not - page, which enables login procedure. But the default route is ignored, when authentication is used. If I launch this from Visual Studio, it navigates me to /Account/AccessDenied?ReturnUrl=%2FPassenger%2FIndex , not /Home/Index. How can I override this?
I found it. And it seems, it it not the fault of .NET Core. It based on headers.
In my case, LocalRedirectPermanent("/Admin/Index") was called several times, therefore, it automatically called "/Admin/Index", bypassing "/Home/Index". I think, it is due to this. Therefore, I have fixed in my browser(Firefox) this way: Reset the history(forms, cookies, etc) and perform in Visual Studio Build->Rebuild Solution. And it started working again. Hope, this helped someone
Related
I need to add a Basic Authentication to a set of API.
DISCLAIMER: The APIs are inside an intranet and contains public data. They can be consumed from external users only through an API gateway where strong authentication and authorization are implemented. This Basic Authentication is needed only to avoid that internal development team calls directly this service. User and password are not the real one.
I've used the package ZNetCS.AspNetCore.Authentication.Basic, version 4.0.0
This is my startup.cs:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
services
.AddAuthentication(BasicAuthenticationDefaults.AuthenticationScheme)
.AddBasicAuthentication(
options =>
{
options.Realm = "My Application";
options.Events = new BasicAuthenticationEvents
{
OnValidatePrincipal = context =>
{
if ((context.UserName.ToLower() == "gateway0107")
&& (context.Password == "jir6STt6437yMAQpl"))
{
var claims = new List<Claim>{
new Claim(ClaimTypes.Name,
context.UserName,
context.Options.ClaimsIssuer)
};
var ticket = new AuthenticationTicket(
new ClaimsPrincipal(new ClaimsIdentity(
claims,
BasicAuthenticationDefaults.AuthenticationScheme)),
new Microsoft.AspNetCore.Authentication.AuthenticationProperties(),
BasicAuthenticationDefaults.AuthenticationScheme);
return Task.FromResult(AuthenticateResult.Success(ticket));
}
return Task.FromResult(AuthenticateResult.Fail("Authentication failed."));
}
};
});
services.AddMvcCore();
services.AddApiVersioning(
options =>
{
options.ReportApiVersions = true;
});
services.AddVersionedApiExplorer(
options =>
{
options.GroupNameFormat = "'v'VVV";
options.SubstituteApiVersionInUrl = true;
});
services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();
services.AddSwaggerGen(
options =>
{
options.OperationFilter<SwaggerDefaultValues>();
options.IncludeXmlComments(XmlCommentsFilePath);
});
services.AddCors(options =>
{
options.AddPolicy(name: "AllowAllOrigins",
builder =>
{
builder.AllowAnyOrigin();
});
});
services.AddControllers(options =>
{
options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(Point)));
options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(Coordinate)));
options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(LineString)));
options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(MultiLineString)));
}).AddNewtonsoftJson(options =>
{
foreach (var converter in NetTopologySuite.IO.GeoJsonSerializer.Create(new GeometryFactory(new PrecisionModel(), 4326)).Converters)
{
options.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
options.SerializerSettings.Converters.Add(converter);
}
}).SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IApiVersionDescriptionProvider provider)
{
app.UseForwardedHeaders();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), "swagger-ui")),
RequestPath = "/swagger-ui"
});
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors("AllowAllOrigins");
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseSwagger();
app.UseSwaggerUI(
options =>
{
// build a swagger endpoint for each discovered API version
foreach (var description in provider.ApiVersionDescriptions)
{
options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
}
});
}
static string XmlCommentsFilePath
{
get
{
var basePath = PlatformServices.Default.Application.ApplicationBasePath;
var fileName = typeof(Startup).GetTypeInfo().Assembly.GetName().Name + ".xml";
return Path.Combine(basePath, fileName);
}
}
}
But testing in Postman and from SwaggerUI I get always 410 Unauthorized.
Setting a breakpoint inside the OnValidatePrincipal, it never gets hit.
Should I have to add something else?
I defined a simple view where I request the user to choose a file to upload.
This file is stored in a model (model of the view) and is then treated in the POST method.
Once the file has been uploaded, I save the new model (result of the file) it into the TempData in order to pass it to the next view to be displayed and later validate the content by the user.
Everything works fine until the redirecttoaction which is not doing anything and I don't know what I'm doing wrong here
Here is an example of what I do:
[HttpGet]
public IActionResult Index()
{
return View();
}
[HttpPost]
public IActionResult Index(ImportIndexViewModel model)
{
if (!ModelState.IsValid)
return View(model);
if (model.File == null)
{
ModelState.AddModelError("File", "File is null");
return View(model);
}
var extension = Path.GetExtension(model.FileName);
if (extension != ".xlsx")
{
ModelState.AddModelError("File extension", "File type is not authorized. Please use the correct template file");
return View(model);
}
var uploads = Path.Combine(_webHostEnvironment.WebRootPath, "uploads");
if (model.File.Length <= 0)
{
ModelState.AddModelError("File size", "File length is <= 0");
return View(model);
}
var resultModel = InterclubsApiClient.GetInterclubsReaderModel(model.File, uploads).GetAwaiter().GetResult();
TempData.Put<InterclubsReaderModel>("InterclubsReaderModel", resultModel);
return RedirectToAction(nameof(ImportController.Upload), typeof(ImportController).GetControllerName());
}
[HttpGet]
public IActionResult Upload()
{
var model = TempData.Get<InterclubsReaderModel>("InterclubsReaderModel");
if (model == null)
return BadRequest(ErrorHelper.GetModelStateDictionary("InterclubsReaderModel", "Model is null when retrieved from TempData"));
return View(model);
}
Upload is working because I can find the file in the uploads folder. The model is also correct because I can find values into it but why the redirect isn't working ?
Instead, the page stays there and I can't do anything on it. If I use Chrome, it says that the website isn't reachable (like missing the link to IIS).
Thanks for your help.
EDIT: In answer to the question: are you sure this is the correct method name given by nameof(...)
Here it is:
SECOND EDIT:
Do you guys think something is wrong here ?
public class Startup
{
public IConfiguration Configuration { get; }
public IWebHostEnvironment Environment { get; }
#region Constructor
public Startup(IConfiguration configuration, IWebHostEnvironment env)
{
Configuration = configuration;
Environment = env;
}
#endregion
#region Configure services
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services
.AddAuthentication("InterclubsCookieAuth")
.AddCookie("InterclubsCookieAuth", config =>
{
config.Cookie.Name = "Interclubs.Cookie";
config.LoginPath = "/Connect/Login";
config.LogoutPath = "/Connect/Logout";
config.ExpireTimeSpan = TimeSpan.FromHours(15);
});
services.AddAuthorization(config =>
{
var defaultAuthBuilder = new AuthorizationPolicyBuilder("InterclubsCookieAuth");
var defaultAuthPolicy = defaultAuthBuilder
.RequireAuthenticatedUser()
.Build();
config.DefaultPolicy = defaultAuthPolicy;
});
services.AddHttpContextAccessor();
services.AddMemoryCache();
services.AddSession();
services.AddMvc(options =>
{
options.EnableEndpointRouting = false;
});
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
// Enables .Net Core to refresh updated views in browser while debugging
var builder = services.AddControllersWithViews();
builder.AddRazorRuntimeCompilation(options =>
{
var libraryPath = Path.GetFullPath(Path.Combine(Environment.ContentRootPath));
options.FileProviders.Add(new PhysicalFileProvider(libraryPath));
});
}
#endregion
#region Configuration
// 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($"/{typeof(HomeController).GetControllerName()}/{nameof(HomeController.Error)}");
app.UseHsts(options => options.MaxAge(days: 365).IncludeSubdomains());
}
app.UseXContentTypeOptions();
app.UseXfo(options => options.SameOrigin());
app.UseXXssProtection(options => options.EnabledWithBlockMode());
app.UseReferrerPolicy(options => options.NoReferrer());
app.UseHttpsRedirection();
var contentTypeProvider = new FileExtensionContentTypeProvider();
if (!contentTypeProvider.Mappings.ContainsKey(".svg"))
{
contentTypeProvider.Mappings.Add(".svg", "image/svg+xml");
}
if (!contentTypeProvider.Mappings.ContainsKey(".woff"))
{
contentTypeProvider.Mappings.Add(".woff", "application/font-woff");
}
if (!contentTypeProvider.Mappings.ContainsKey(".woff2"))
{
contentTypeProvider.Mappings.Add(".woff2", "application/font-woff2");
}
var staticFilesOptions = new StaticFileOptions
{
ContentTypeProvider = contentTypeProvider
};
app.UseStaticFiles(staticFilesOptions);
app.UseSession();
app.UseAuthentication();
app.UseAuthorization();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: $"{{controller={typeof(ConnectController).GetControllerName()}}}/{{action={nameof(ConnectController.Login)}}}");
});
}
#endregion
}
I solved it: it comes from the TempData.
In .NetCore 3.0 which I'm using, the TempData needs to use Cookies or Session.
I enabled the Session and then the redirect was working again without changing anything to my code !
Hope this will help others.
I am building a website in dotnet core and have recently started using claims based authentication and authorization.
In a view component I am checking if the user has access to a policy.
public NavigationViewComponent(
IContextManager contextManager,
IAuthorizationService authorizationService)
{
_contextManager = contextManager;
_authorizationService = authorizationService;
}
public async Task<IViewComponentResult> InvokeAsync()
{
var showAdmin = _contextManager.Principal != null &&
(await _authorizationService.AuthorizeAsync(_contextManager.Principal, "Admin")).Succeeded;
var vm = new NavigationViewModel
{
ShowAdmin = showAdmin
};
return View(vm);
}
However, I am receiving the Exception InvalidOperationException: No policy found: Admin..
My startup.cs contains the following inside the ConfigureServices method:
services.AddAuthorization(options =>
{
options.AddPolicy("Admin",
policy => policy.Requirements.Add(new HasPermissionRequirement("ADMIN")));
});
What else do I need to configure in order to get this to work correctly?
For reference I am registering 3 additional IAuthorizationHandler implementations and 1 IAuthorizationPolicyProvider.
Edit
For reference, the whole startup.cs looks something similar to this.
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
// Name and policy settings
options.Cookie.Name = "account";
options.Cookie.SameSite = SameSiteMode.Strict;
options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
options.Cookie.HttpOnly = true;
// Sign the user out after 28 days of inactivity
options.SlidingExpiration = true;
options.ExpireTimeSpan = TimeSpan.FromDays(28);
// Challenge actions
options.LoginPath = new PathString("/account/login");
options.ReturnUrlParameter = "returnUrl";
});
services.AddAuthorization(options =>
{
options.AddPolicy("Admin",
policy => policy.Requirements.Add(new HasPermissionRequirement("ADMIN")));
});
services.AddSingleton<IAuthorizationHandler, HasPermissionHandler>();
services.AddSingleton<IAuthorizationHandler, StrategyAuthorizationCrudHandler>();
services.AddSingleton<IAuthorizationHandler, UserAuthorizationCrudHandler>();
services.AddSingleton<IAuthorizationPolicyProvider, HasPermissionPolicyProvider>();
// AddAntiforgery, AddSession,AddDistributedRedisCache and AddDataProtection omitted
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddJsonOptions(options =>
{
options.SerializerSettings.ReferenceLoopHandling =
ReferenceLoopHandling.Ignore;
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
app.UseCookiePolicy(new CookiePolicyOptions
{
CheckConsentNeeded = httpContext => false,
MinimumSameSitePolicy = SameSiteMode.Strict,
Secure = CookieSecurePolicy.SameAsRequest
});
app.UseAuthentication();
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
app.UseStaticFiles();
var supportedCultures = new[]
{
new CultureInfo("en-GB")
};
app.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture(supportedCultures[0]),
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures
});
app.UseSession();
app.UseMiddleware<UserMiddleware>();
app.UseMiddleware<LoggingMiddleware>();
app.UseMvc(routes =>
{
routes.MapRoute(
"default",
"{controller=Home}/{action=Index}/{id?}");
});
}
HasPermissionRequirement.cs
public class HasPermissionRequirement : IAuthorizationRequirement
{
public string Permission { get; private set; }
public HasPermissionRequirement(string permission)
{
Permission = permission;
}
}
HasPermissionHandler.cs
public class HasPermissionHandler : AuthorizationHandler<HasPermissionRequirement>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
HasPermissionRequirement requirement)
{
var hasPermission = context.User.HasClaim("Permission", requirement.Permission);
if (hasPermission)
context.Succeed(requirement);
return Task.CompletedTask;
}
}
HasPermissionPolicyProvider.cs
public class HasPermissionPolicyProvider : IAuthorizationPolicyProvider
{
private const string PolicyPrefix = "HasPermission";
public Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
{
if (!policyName.StartsWith(PolicyPrefix, StringComparison.OrdinalIgnoreCase))
return Task.FromResult<AuthorizationPolicy>(null);
var permission = policyName.Substring(PolicyPrefix.Length);
var policy = new AuthorizationPolicyBuilder();
policy.AddRequirements(new HasPermissionRequirement(permission));
return Task.FromResult(policy.Build());
}
public Task<AuthorizationPolicy> GetDefaultPolicyAsync() =>
Task.FromResult(new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build());
}
I've managed to solve this by taking a closer look at the Microsoft documentation after being pointed in the right direction.
https://github.com/aspnet/Docs/blob/master/aspnetcore/security/authorization/iauthorizationpolicyprovider.md#multiple-authorization-policy-providers
When using custom IAuthorizationPolicyProvider implementations, keep in mind that ASP.NET Core only uses one instance of IAuthorizationPolicyProvider. If a custom provider isn't able to provide authorization policies for all policy names, it should fall back to a backup provider.
As a result I changed the implementation of my HasPermissionPolicyProvider to CustomPolicyProvider and the content is below:
public class CustomPolicyProvider : DefaultAuthorizationPolicyProvider
{
private const string PermissionPolicyPrefix = "HasPermission";
public CustomPolicyProvider(IOptions<AuthorizationOptions> options) : base(options)
{
}
public override async Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
{
var policy = await base.GetPolicyAsync(policyName);
if (policy != null) return policy;
if (policyName.StartsWith(PermissionPolicyPrefix, StringComparison.OrdinalIgnoreCase))
{
var permission = policyName.Substring(PermissionPolicyPrefix.Length);
return new AuthorizationPolicyBuilder()
.AddRequirements(new HasPermissionRequirement(permission))
.Build();
}
return null;
}
}
This means that you can only have one PolicyProvider which must handle all your logic. The change is to ensure that it calls the default implementation if you require multiple handler logic.
I am trying to find a way to prevent my aspnetcore application to add "?ReturnUrl=" to the URL. Does anyone know how to do it, using some kind of middleware.
I tried doing it like below but it did not have any effect:
public class RequestHandlerMiddleware
{
private readonly RequestDelegate _next;
public RequestHandlerMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
if(context.Request.QueryString.HasValue && context.Request.QueryString.Value.Contains("?ReturnUrl="))
{
context.Request.QueryString = new QueryString(string.Empty);
}
await _next.Invoke(context);
}
}
public static class RequestHandlerMiddlewareExtension
{
public static IApplicationBuilder UseRequestHandlerMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestHandlerMiddleware>();
}
}
Registration in startup.cs:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/error");
}
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseAuthentication();
app.UseRequestHandlerMiddleware();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action=Index}/{id?}");
});
}
Lastly, I have also tried some (tweaked) approaches from the older post regarding the same issue for .NET frameworks here (on stackoverflow) but also failed
Edit: I am not using any additional AuthorizationAttribute / Handler other then the 'standard' [Authorize] attribute. Only:
services.AddAuthorization();
Edit 2: I totally forgot that I also register a portion of the startup elsewhere in the application since it is shared:
public static IServiceCollection Load(IServiceCollection services, IConfiguration config)
{
services.AddDbContext<SqlContext>(options =>
{
options.UseSqlServer(config.GetConnectionString("DefaultConnection"));
});
services.AddIdentity<User, Role>(options =>
{
options.Lockout = new LockoutOptions
{
AllowedForNewUsers = true,
DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30),
MaxFailedAccessAttempts = 5
};
})
.AddEntityFrameworkStores<SqlContext>()
.AddDefaultTokenProviders()
.AddUserStore<UserStore<User, Role, SqlContext, Guid>>()
.AddRoleStore<RoleStore<Role, SqlContext, Guid>>()
.AddUserManager<ApplicationUserManager>();
services.Configure<IdentityOptions>(options =>
{
options.Password.RequireDigit = false;
options.Password.RequiredLength = 5;
options.Password.RequireLowercase = true;
options.Password.RequireUppercase = false;
options.Password.RequireNonAlphanumeric = true;
});
services.ConfigureApplicationCookie(options =>
options.Events = new CookieAuthenticationEvents
{
OnRedirectToLogin = ctx =>
{
if (ctx.Request.Path.StartsWithSegments("/api") &&
ctx.Response.StatusCode == (int)HttpStatusCode.OK)
{
ctx.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
}
else if (ctx.Response.StatusCode == (int)HttpStatusCode.Forbidden)
{
ctx.Response.StatusCode = (int)HttpStatusCode.Forbidden;
}
else
{
ctx.Response.Redirect(ctx.RedirectUri);
}
return Task.FromResult(0);
}
});
return services;
}
The first thing that comes to mind is :
[HttpGet]
public IActionResult LogIn()
{
if (!string.IsNullOrEmpty(Request.QueryString.Value))
return RedirectToAction("Login");
return View();
}
Which will remove QueryString part from the URL so that "ReturnUrl" will not stay on user address-bar for long and will reject any QueryString.
Better workaround would be creating your own version of AuthorizeAttribute which will not put a ReturnUrl in QueryString but it seems with new policy based authorization approach coming around, customizing AuthorizeAttribute is discouraged. more
It might be also possible with policy based approach and creating a custom AuthorizationHandler.
(I will post an update as soon as I try it out)
Plz, help in my trouble.
I created new application in MS VS 2017. Type ASP.NET Core 2 MVC
I can't find solution for my problem with authorize.
I added to Startup
public void ConfigureServices(IServiceCollection services) {
services.AddScoped<USDb, USDb>();
services.Scan(scan => scan.FromAssemblyOf<USDb>()
.AddClasses()
.AsImplementedInterfaces());
InjectionContainer = services.BuildServiceProvider();
services.AddMvc();
//Auth
services.AddAuthentication(o => {
o.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, o => {
o.LoginPath = new PathString("/Account/Login");
o.ReturnUrlParameter = "RedirectUrl";
o.AccessDeniedPath = new PathString("/Account/AccessDenied");
o.LogoutPath = new PathString("/Account/Logout");
o.ExpireTimeSpan = TimeSpan.FromDays(1);
o.SlidingExpiration = true;
o.Cookie.SameSite = SameSiteMode.Strict;
o.Cookie.Name = ".USAUTH";
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
} else {
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseMvc(routes => {
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
app.UseAuthentication();
}
My AccountController method
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginModel model, string redirectUrl = null) {
if (ModelState.IsValid) {
await Authenticate("login");
return Redirect(redirectUrl);
}
return View();
}
private async Task Authenticate(string userName) {
var claims = new List{ new Claim(ClaimsIdentity.DefaultNameClaimType, userName) };
ClaimsIdentity id = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(id));
}
When I try to go Home/Index application redirect me to account - it's very good. But after I entered login data and submited it to login method application redirect me to login page again... and again.... etc
But cookies appeared, but application not created HttpContext.User.Identity and still redirecting me to login page....
And I don't know what todo(((( please help(( I lose the hope(
You must call app.UseAuthentication(); before app.UseMvc(...);.
Banal error but I had the same problem a while ago after upgrading to asp.net core 2.0.