Assigning a user to a Role inside asp.net core will return this error “You do not have access to this resource.”

对着背影说爱祢 提交于 2019-12-11 15:21:33

问题


I created a new asp.net core web application which uses individual user accounts. now i am trying to implement a simple role assignment scenario.

so i register a test user, where the user got added inside the AspNetUser table:-

then i add a new Role named "Administrator" inside the AspNetRole:-

then i added a new AspNetUserRole to link the user to the Role:-

then i added the following Authorize annotation on the About action method:-

[Authorize(Roles = "Administrator")]
        public IActionResult About()
        {
            ViewData["Message"] = "Your application description page.";

            return View();
        }

but when i try to access the About action method using the user, i got this error:-

You do not have access to this resource."

EDIT

Here is the startup.cs , which i have not modified, so i think it contain the built-in code:-

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using WebApplication2.Data;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace WebApplication2
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(
                    Configuration.GetConnectionString("DefaultConnection")));
            services.AddDefaultIdentity<IdentityUser>()
                .AddEntityFrameworkStores<ApplicationDbContext>();

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();

            app.UseAuthentication();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}

回答1:


I guess you manually create role and link role in AspNetUserRoletable after creating your user . Please don't forget to Logout user and login again , so role claims will get/update the new added role .




回答2:


Short answer

Add IdentityRole :

services.AddDefaultIdentity<IdentityUser>()
    .AddRoles<IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>();

Long Answer

For properly using of roles/policies, you need to follow the below steps:

  • configure ApplicationDbContext for using IdentityRole
  • configure Identity service to use IdentityRole
  • configure application cookie
  • define authorization policies
  • configure authorization for razor pages

Notice : if you are using razor pages, Authorization attributes must be applied to the PageModel model not the actions

before proceeding with the solution, it is worth to mention that it is a best practice to use custom user and role models instead of IdentityUser and IdentityModel. This will help you add custom fields to the user and role easily.

So, first lets create our custom user and role models:

public class AppUser : IdentityUser
{
    //custom fields can be defined here
}

public class AppRole : IdentityRole
{
    //custom fields can be defined here
}

public class AppUserRole : IdentityUserRole<string>
{
    public virtual AppUser User { get; set; }
    public virtual AppRole Role { get; set; }
}

Now we can start with configuring ApplicationDbContext:

public class ApplicationDbContext : IdentityDbContext<AppUser, AppRole, string, IdentityUserClaim<string>, AppUserRole, IdentityUserLogin<string>, IdentityRoleClaim<string>, IdentityUserToken<string>>
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        // Customize the ASP.NET Identity model and override the defaults if needed.
        // For example, you can rename the ASP.NET Identity table names and more.
        // Add your customizations after calling base.OnModelCreating(builder);
        // AppUserRole relationship solution from so
        // https://stackoverflow.com/questions/51004516/net-core-2-1-identity-get-all-users-with-their-associated-roles/51005445#51005445

        builder.Entity<AppUserRole>(userRole =>
        {
            userRole.HasKey(ur => new { ur.UserId, ur.RoleId });

            userRole.HasOne(ur => ur.Role)
                .WithMany(r => r.UserRoles)
                .HasForeignKey(ur => ur.RoleId)
                .IsRequired();

            userRole.HasOne(ur => ur.User)
                .WithMany(r => r.UserRoles)
                .HasForeignKey(ur => ur.UserId)
                .IsRequired();
            });
        }
    }
}
  • configuring Identity
services.AddIdentity<AppUser, AppRole>(ops =>
{
    ops.SignIn.RequireConfirmedEmail = true;

    // Lockout settings
    ops.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
    ops.Lockout.MaxFailedAccessAttempts = 9;

    ops.Lockout.AllowedForNewUsers = true;

    // User settings
    ops.User.RequireUniqueEmail = true;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
  • configure application cookie
services.ConfigureApplicationCookie(ops =>
{
     // Cookie settings
     ops.Cookie.HttpOnly = false;
     ops.ExpireTimeSpan = TimeSpan.FromMinutes(30);

     // If the LoginPath isn't set, ASP.NET Core defaults the path to /Account/Login.
     ops.LoginPath = $"/Identity/Account/Login";

     // If the AccessDeniedPath isn't set, ASP.NET Core defaults the path to /Account/AccessDenied.
     ops.AccessDeniedPath = $"/Identity/Account/AccessDenied";
     ops.SlidingExpiration = true;
});
  • define authorization policies
services.AddAuthorization(ops =>
{
    ops.AddPolicy("Administrator", policy =>
    {
         policy.RequireRole("Administrator");
    });
});

Now it is possible to use roles/policies in different ways:

1- define authorization policies in startup

services.AddMvc()
    .AddRazorPagesOptions(ops =>
    {
        ops.Conventions.AuthorizeFolder("/", "Administrator");
    })
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

2- apply authorization attributes on actions in case of MVC

[Authorize(Roles = "Administrator")]
public IActionResult About()
{
    ViewData["Message"] = "Your application description page.";
    return View();
}

3- or apply policy on PageModel for Razor Pages

[Authorize(Policy = "Administrator")]
public class AboutModel : PageModel
{
    //-----
}

[UPDATE]

following to your comment below; Let's consider that you will develop a news website management panel; basically you will need roles like Admins to manage the site settings and Authors to post the news pages, and probably Managers to approve the posted news. With this scenario you can survive with the default Identity settings and role based authorization.

But for example; if you need to allow only authors with more than 100 posted articles and are older than 25 to be able to approve their posts without the Managers approval then you need to customize the IdentityUser and use policy/claim based authorization, in this case the long answer will help you more to develop the application.

you can read more about authorization in the docs




回答3:


Your identity service is not configured for roles. AddDefaultIdentity cannot handle roles. You need AddIdentity

Instead of:

services.AddDefaultIdentity<IdentityUser>().AddEntityFrameworkStores<ApplicationDbContext>();

Try:

services.AddIdentity<IdentityUser, IdentityRole>().AddEntityFrameworkStores<ApplicationDbContext>().AddDefaultTokenProviders();


来源:https://stackoverflow.com/questions/55754649/assigning-a-user-to-a-role-inside-asp-net-core-will-return-this-error-you-do-no

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!