In my net core 5 application i need to set two login path, one for administrators in admin area and other one will be for users area, i have configured application cookie but i cant access the current url in ConfigureServices so i cant change the login path depends on the url
My code
public static IServiceCollection AddIdentityServices(this IServiceCollection services, IConfiguration _config)
{
AppIdentitySettings appIdentitySettings = _config.GetSection("AppIdentitySettings").Get<AppIdentitySettings>();
services.AddIdentity<CI_User, CI_Role>(opt =>
{
//password settings
opt.Password.RequiredLength = appIdentitySettings.Password.RequiredLength;
opt.Password.RequireDigit = appIdentitySettings.Password.RequireDigit;
opt.Password.RequiredUniqueChars = appIdentitySettings.Password.RequiredUniqueChars;
opt.Password.RequireUppercase = appIdentitySettings.Password.RequireUppercase;
opt.Password.RequireLowercase = appIdentitySettings.Password.RequireLowercase;
opt.Password.RequireNonAlphanumeric = appIdentitySettings.Password.RequireNonAlphanumeric;
//user settings
//opt.User.AllowedUserNameCharacters = "ghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP";
opt.User.RequireUniqueEmail = appIdentitySettings.User.RequireUniqueEmail;
//Lockout settings
//opt.Lockout.AllowedForNewUsers = false;
})
.AddEntityFrameworkStores<_ModelsContext>()
.AddDefaultTokenProviders();
//configure cookie
services.ConfigureApplicationCookie(opt =>
{
// Cookie settings
opt.Cookie.HttpOnly = true;
opt.ExpireTimeSpan = TimeSpan.FromMinutes(60);
opt.LoginPath = "/ar/Home/App";
opt.AccessDeniedPath = "/Identity/Account/AccessDenied";
opt.SlidingExpiration = true;
});
return services;
}
How can i do this situation !?
----------UPDATE---------
I have found two solutions, or you can call it a workaround
Solution one : add two different Authentication scheme in start up ConfigureServices
string defaultCulture = _config.GetValue<string>("DefaultCulture");
services.AddAuthentication(opt => { opt.DefaultScheme = "UserAuth"; })
.AddCookie("UserAuth", opt =>
{
opt.LoginPath = $"/{defaultCulture}/User/Login";
opt.AccessDeniedPath = $"/{defaultCulture}/Account/AccessDenied/";
})
.AddCookie("AdminAuth", opt =>
{
opt.LoginPath = $"/{defaultCulture}/Admin/About";
opt.AccessDeniedPath = $"/{defaultCulture}/Admin/Account/AccessDenied/";
});
And for usage
[Authorize(AuthenticationSchemes = "AdminAuth")]
Problems with solution one : If you have a multi language application, you cannot redirect the user dynamically to his chosen culture
Solution two : add custom authorization attribute
public class CustomAuthorizeAttribute : Attribute, IAuthorizationFilter
{
public bool IsAdmin { get; set; } = false;
public void OnAuthorization(AuthorizationFilterContext context)
{
bool hasAllowAnonymous = context.ActionDescriptor.EndpointMetadata.Any(em => em.GetType() == typeof(AllowAnonymousAttribute));
bool isAuth = context.HttpContext.User.Identity.IsAuthenticated;
if (!isAuth && !hasAllowAnonymous)
{
string redirectUrl = context.HttpContext.Request.Path.Value;
if (IsAdmin)
context.Result = new RedirectToActionResult("Index", "About", new { redirectUrl = redirectUrl, area = "Admin" });
else
context.Result = new RedirectToActionResult("App", "Home", new { redirectUrl = redirectUrl });
}
}
}
Problems with solution two : You cannot do the same logic if you inherited from Authorize attribute, so you will lose all of authorize attribute benefits !