【问题标题】:Identity Role is not getting added to user身份角色未添加到用户
【发布时间】:2020-01-24 05:16:41
【问题描述】:

我想将 JWT auth 用于我的 web api 和 cookie auth 用于 Razor 页面。 我对控制器使用策略授权。在我的Startup.cs 中使用此配置的 Razor 页面一切正常:

services.AddIdentity<User, Role>(opt =>{
                opt.Password.RequireDigit = false;
                opt.Password.RequiredLength = 4;
                opt.Password.RequireNonAlphanumeric = false;
                opt.Password.RequireUppercase = false;
                opt.Password.RequireLowercase = false;
            })
            .AddEntityFrameworkStores<DataContext>()
            .AddRoleValidator<RoleValidator<Role>>()
            .AddRoleManager<RoleManager<Role>>()
            .AddSignInManager<SignInManager<User>>();

但是我的控制器端点不工作,当我使用下面的那个时它工作:

IdentityBuilder builder = services.AddIdentityCore<User>(opt =>
            {
                opt.Password.RequireDigit = false;
                opt.Password.RequiredLength = 4;
                opt.Password.RequireNonAlphanumeric = false;
                opt.Password.RequireUppercase = false;
                opt.Password.RequireLowercase = false;
            });

但是角色没有被添加到用户声明中,因此我的 Razor 页面的授权策略属性总是返回 Access Denied

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.AddDbContext<DataContext>(opt => opt.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

            services.ConfigureApplicationCookie(options =>
            {
                // Cookie settings
                options.Cookie.HttpOnly = true;
                options.ExpireTimeSpan = TimeSpan.FromDays(1);
                options.LoginPath = "/Account/Login";
                options.AccessDeniedPath = "/Account/AccessDenied";
                options.SlidingExpiration = true;
                options.Cookie.Name = Configuration.GetSection("AppSettings:AuthCookieName").Value;
            });

            // services.AddIdentity<User, Role>(opt =>{
            //     opt.Password.RequireDigit = false;
            //     opt.Password.RequiredLength = 4;
            //     opt.Password.RequireNonAlphanumeric = false;
            //     opt.Password.RequireUppercase = false;
            //     opt.Password.RequireLowercase = false;
            // });

            IdentityBuilder builder = services.AddIdentityCore<User>(opt =>
            {
                opt.Password.RequireDigit = false;
                opt.Password.RequiredLength = 4;
                opt.Password.RequireNonAlphanumeric = false;
                opt.Password.RequireUppercase = false;
                opt.Password.RequireLowercase = false;
            });

            builder = new IdentityBuilder(builder.UserType, typeof(Role), builder.Services);
            builder.AddEntityFrameworkStores<DataContext>();
            builder.AddRoleValidator<RoleValidator<Role>>();
            builder.AddRoleManager<RoleManager<Role>>();
            builder.AddSignInManager<SignInManager<User>>();

            services.AddAuthorization(options =>{
                 options.AddPolicy("CorrectUserIdRequested", policy=>{
                    policy.AddRequirements(new CorrectUserIdRequestedRequirement());
                });
                options.AddPolicy("RequireAdminRole", policy => policy.RequireRole("admin"));
                options.AddPolicy("RequireUserRole", policy => policy.RequireRole("admin","user"));
            });
            services.AddMvc(options => {
                var policy = new AuthorizationPolicyBuilder()
                    .RequireAuthenticatedUser()
                    .Build();
                options.Filters.Add(new AuthorizeFilter(policy));
            }).
            SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
            .AddJsonOptions(opt =>
                            {
                                opt.SerializerSettings.ReferenceLoopHandling =
                                Newtonsoft.Json.ReferenceLoopHandling.Ignore;
                            });

            // Authentication Scheme
            services.AddAuthentication(IdentityConstants.ApplicationScheme)
                    .AddCookie(IdentityConstants.ApplicationScheme, options =>
                    {

                        //if url start with "/api" use jwt instead
                        options.ForwardDefaultSelector = httpContext => httpContext.Request.Path.StartsWithSegments("/api") ? JwtBearerDefaults.AuthenticationScheme : null;
                    })
                    .AddJwtBearer(o =>
                    {
                        o.TokenValidationParameters = new TokenValidationParameters
                        {
                            ValidateIssuerSigningKey = true,
                            IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII
                            .GetBytes(Configuration.GetSection("AppSettings:Token").Value)),
                            ValidateIssuer = false,
                            ValidateAudience = false
                        };
                    });
            Mapper.Reset();
            services.AddCors();
            services.AddAutoMapper(typeof(Startup));
            //Injections
            services.AddTransient<Seed>();
            services.AddScoped<AuthService, AuthServicePasswordless>();
            services.AddScoped<IUserRepository, UserRepository>();
            services.AddScoped<INotificationService, SmsNotifyService>();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, Seed seeder)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler(builder => {
                    builder.Run(async context => {
                        context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

                        var error = context.Features.Get<IExceptionHandlerFeature>();
                        if(error != null){
                            context.Response.AddApplicationError(error.Error.Message);
                            await context.Response.WriteAsync(error.Error.Message);
                        }
                    });
                });                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                // app.UseHsts();
            }

            // app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();
            seeder.SeedUsers();
            app.UseAuthentication();
            app.UseMvc(routes =>
            {                
                routes.MapRoute(
                    name: null,
                    template: "{area:exists}/{controller=Dashboard}/{action=Index}/{id?}");

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


//Controller
[Authorize(Policy = "RequireAdminRole")]
    [Area("Admin")]
    public class DashboardController : Controller
    {
        public IActionResult Index(){
            return View();
        }
    }

【问题讨论】:

    标签: c# asp.net-core asp.net-core-identity


    【解决方案1】:

    注意您创建了一个全新的IdentityBuilder,然后配置了新创建的IdentityBuilder而不是services.AddIdentityCore&lt;&gt;()返回的那个

    IdentityBuilder builder = services.AddIdentityCore(opt => { opt.Password.RequireDigit = false; opt.Password.RequiredLength = 4; opt.Password.RequireNonAlphanumeric = false; opt.Password.RequireUppercase = false; opt.Password.RequireLowercase = false; }); builder = new IdentityBuilder(builder.UserType, typeof(Role), builder.Services); ...配置构建器

    如何解决:

    要解决此问题,您需要配置在服务容器中注册的相同构建器

    builder = new IdentityBuilder(builder.UserType, typeof(IdentityRole), builder.Services);

    最后别忘了先退出重新登录让用户获得角色。


    附带说明,您不需要添加编写这么多代码来配置身份验证。更好的方法是调用AddDefaultIdentity&lt;User&gt;() 而不是AddIdentityCore() 来简化您的代码:

    IdentityBuilder builder = services.AddDefaultIdentity(opt => { ... }) .AddRoles() .AddDefaultTokenProviders() .AddEntityFrameworkStores() ; builder = new IdentityBuilder(builder.UserType, typeof(Role), builder.Services); builder.AddEntityFrameworkStores(); builder.AddRoleValidator>(); builder.AddRoleManager>(); builder.AddSignInManager>(); 罢工> …… services.Configure(IdentityConstants.ApplicationScheme,opt=>{ //如果url以“/api”开头,使用jwt代替 opt.ForwardDefaultSelector = httpContext => httpContext.Request.Path.StartsWithSegments("/api") ? JwtBearerDefaults.AuthenticationScheme:空; }); services.AddAuthentication(IdentityConstants.ApplicationScheme) .AddCookie(IdentityConstants.ApplicationScheme, options => { //如果url以“/api”开头,使用jwt代替 options.ForwardDefaultSelector = httpContext => httpContext.Request.Path.StartsWithSegments("/api") ? JwtBearerDefaults.AuthenticationScheme:空; }) .AddJwtBearer(o => { ... });

    演示

    【讨论】:

    • 谢谢。我的 web api 正在工作,但我得到: InvalidOperationException:默认身份 UI 布局需要部分视图“_LoginPartial”。我不想用默认的ui,我也设置了options.LoginPath = "/Account/Login"; options.LogoutPath = "/帐户/注销"; options.AccessDeniedPath = "/Account/AccessDenied";在 cookie 选项中
    • @KaviArshan 请将services.AddDefaultIdentity&lt;User&gt; 更改为services.AddIdentity&lt;User,Role&gt;() :)
    • @KaviArshan 哦,我明白了。我没有告诉你configure func:IdentityBuilder builder = services.AddIdentity&lt;User,Role&gt;(opt =&gt; { opt.Password.RequireDigit = false; ..... other configurations.... })
    • 我只是忘记将角色添加到 AddIdenitty 非常感谢,您拯救了我的一天
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-16
    • 1970-01-01
    • 2018-09-25
    • 1970-01-01
    • 2016-02-11
    • 2014-08-08
    • 2021-11-18
    相关资源
    最近更新 更多