SQL Server ASP.NET Core Identity Role: Access error even though the role is defined

66bbxpm5  于 5个月前  发布在  .NET
关注(0)|答案(1)|浏览(48)

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.

1l5u6lss

1l5u6lss1#

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);

相关问题