In my project, the user area is kept on the root side and admin is in areas. The login page, layouts and views of both areas are different from each other. How will I do the role setting in these two pages. I mean like this,
There are multiple users on the admin side, like admin A can't access page-1, admin B can't access page-2... User side is the same way.
Admin and user side should have separate AccessDeniedPath paths, and if not logged in, LoginPath should have separate paths.
Example:
Admin: Management/Login/Index
User: Login/Index
I should also check this when I log in. If the user is logged in by admin, they should get a "You are not authorized" warning.
This is the code I tried,
With this code, I can control while logging in, but I cannot make controller based role.
Program.cs,
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpClient();
builder.Services.AddControllersWithViews();
builder.Services.AddDbContext<Context>();
builder.Services.AddIdentity<AppUser, AppRole>(options =>
{
options.User.RequireUniqueEmail = true;
}).AddEntityFrameworkStores<Context>().AddErrorDescriber<CustomIdentityValidator>().AddDefaultTokenProviders().AddRoles<AppRole>();
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie("UserLogin", options =>
{
options.LoginPath = "/Login/Index";
options.Cookie.Name = "UserLoginCookie";
options.ExpireTimeSpan = TimeSpan.FromMinutes(60);
options.Events = new CookieAuthenticationEvents
{
OnValidatePrincipal = context =>
{
var now = DateTime.UtcNow;
var expires = context.Properties.ExpiresUtc;
if (expires != null && expires.Value < now)
{
context.RejectPrincipal();
context.ShouldRenew = true;
context.Response.Redirect("/Login/Index");
}
return Task.CompletedTask;
}
};
})
.AddCookie("ManagementLogin", options =>
{
options.LoginPath = "/Management/Login/Index";
options.Cookie.Name = "ManagementLoginCookie";
options.ExpireTimeSpan = TimeSpan.FromMinutes(60);
options.Events = new CookieAuthenticationEvents
{
OnValidatePrincipal = context =>
{
var now = DateTime.UtcNow;
var expires = context.Properties.ExpiresUtc;
if (expires != null && expires.Value < now)
{
context.RejectPrincipal();
context.ShouldRenew = true;
context.Response.Redirect("/Management/Login/Index");
}
return Task.CompletedTask;
}
};
});
builder.Services.AddSession();
builder.Services.AddDistributedMemoryCache();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseSession();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.MapControllerRoute(
name: "areas",
pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
app.Run();
LoginController.cs,
[AllowAnonymous]
public class LoginController : Controller
{
private readonly SignInManager<AppUser> _signInManager;
private readonly UserManager<AppUser> _userManager;
public LoginController(SignInManager<AppUser> signInManager, UserManager<AppUser> userManager)
{
_signInManager = signInManager;
_userManager = userManager;
}
[HttpGet]
public IActionResult Index()
{
return View();
}
[HttpPost]
public async Task<IActionResult> Index(LoginDto loginDto)
{
LoginValidator validationRules = new LoginValidator();
ValidationResult validationResult = await validationRules.ValidateAsync(loginDto);
if (validationResult.IsValid)
{
var user = await _userManager.FindByNameAsync(loginDto.UserName);
if (user != null)
{
var result = await _signInManager.CheckPasswordSignInAsync(user, loginDto.Password, true);
if (result.Succeeded)
{
if (!await _userManager.IsEmailConfirmedAsync(user))
{
TempData["Mail"] = "Mail";
return RedirectToAction("Confirm", "Confirmation");
}
else
{
var login = await _signInManager.PasswordSignInAsync(loginDto.UserName, loginDto.Password, true, true);
if (login.Succeeded)
{
if (await _userManager.IsInRoleAsync(user, UserRoles.Kullanici))
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, user.UserName),
};
var userIdentity = new ClaimsIdentity(claims, "UserLogin");
var userPrincipal = new ClaimsPrincipal(userIdentity);
await HttpContext.SignInAsync("UserLogin", userPrincipal);
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError("", "Bu sayfaya erişim izniniz bulunmamaktadır.");
return View();
}
}
else if (login.IsLockedOut)
{
ModelState.AddModelError("", "Fazla sayıda hatalı giriş yaptığınız için hesabınız kilitlendi. Lütfen daha sonra tekrar deneyiniz. Şifrenizi hatırlamıyorsanız 'Şifremi Unuttum' kısmından yeni bir şifre belirleyebilirsiniz.");
}
else
{
ModelState.AddModelError("", "Hatalı Kullanıcı Adı veya Şifre");
}
}
}
else if (result.IsLockedOut)
{
ModelState.AddModelError("", "Fazla sayıda hatalı giriş yaptığınız için hesabınız kilitlendi. Lütfen daha sonra tekrar deneyiniz. Şifrenizi hatırlamıyorsanız 'Şifremi Unuttum' kısmından yeni bir şifre belirleyebilirsiniz.");
}
else
{
ModelState.AddModelError("", "Hatalı Kullanıcı Adı veya Şifre");
}
}
else
{
ModelState.AddModelError("", "Böyle Bir Hesap Bulunamadı");
}
}
else
{
foreach (var item in validationResult.Errors)
{
ModelState.AddModelError(item.PropertyName, item.ErrorMessage);
}
}
return View();
}
[HttpGet]
public IActionResult ForgotPassword()
{
return View();
}
}
HomeController.cs,
[Authorize(AuthenticationSchemes = "UserLogin")]
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
}
HomeController.cs(edited),
**[Authorize(AuthenticationSchemes = "UserLogin", Roles="User-IT")]**
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
}
If I use it like this, I get an access denied warning even though I have User-IT authorization.
When you use the [Authorize]
attribute with both AuthenticationSchemes
and Roles
specified, the authorization logic requires satisfying both conditions. In other words, a user must be authenticated using the specified authentication scheme (UserLogin
) and must also belong to the specified role (User-IT
) to access the action.
Then when you use cookie authentication, you need add the role to the claims and login the user by HttpContext.SignInAsync
:
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, user.UserName),
new Claim(ClaimTypes.Role, "User-IT") //add this line...
};
var userIdentity = new ClaimsIdentity(claims, "UserLogin");
var userPrincipal = new ClaimsPrincipal(userIdentity);
await HttpContext.SignInAsync("UserLogin", userPrincipal);
Declare with the authorize attribute like below:
[Authorize(AuthenticationSchemes = "UserLogin", Roles = "User-IT")]
Reference:
https://stackoverflow.com/a/64766150/11398810
You may mix cookie authentication with Identity. For how to use Identity authentication with roles, you can leverage the built-in [Authorize] attribute along with the Roles parameter([Authorize( Roles = "User-IT")]
) and login by the following code:
var login = await _signInManager.PasswordSignInAsync(loginDto.UserName, loginDto.Password, true, true);