Как добавить личность на основе ролей в приложение Razor Pages? - PullRequest
0 голосов
/ 22 апреля 2019

Я настраиваю новое приложение Razor Pages и хочу добавить авторизацию на основе ролей. В Интернете есть много учебных пособий о том, как это сделать с помощью приложения ASP.NET MVC, но не с помощью страниц Razor. Я пробовал несколько решений, но у меня ничего не работает. На данный момент у меня есть проблема, как заполнить базы данных ролями и добавить эти роли каждому новому зарегистрированному пользователю.

Вот так выглядит мой Startup.cs:

public async Task ConfigureServices(IServiceCollection services)
{
        var serviceProvider = services.BuildServiceProvider();

        services.Configure<CookiePolicyOptions>(options =>
        {
            // This lambda determines whether user consent for non-essential cookies is needed for a given request.
            options.CheckConsentNeeded = context => true;
        });

        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
        services.AddDefaultIdentity<IdentityUser>(config =>
        {
            config.SignIn.RequireConfirmedEmail = true;
        })
            .AddRoles<IdentityRole>()
            .AddDefaultUI(UIFramework.Bootstrap4)
            .AddEntityFrameworkStores<ApplicationDbContext>();

        services.AddAuthorization(config =>
        {
            config.AddPolicy("RequireAdministratorRole",
                policy => policy.RequireRole("Administrator"));
        });

        services.AddTransient<IEmailSender, EmailSender>();
        services.Configure<AuthMessageSenderOptions>(Configuration);

        services.AddRazorPages()
            .AddNewtonsoftJson()
            .AddRazorPagesOptions(options => {
                options.Conventions.AuthorizePage("/Privacy", "Administrator");
            });

        await CreateRolesAsync(serviceProvider);
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            // 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();

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages();
        });
    }

    /// <summary>
    /// Method that creates roles
    /// </summary>
    /// <param name="serviceProvider"></param>
    /// <returns></returns>
    private async Task CreateRolesAsync(IServiceProvider serviceProvider)
    {
        //adding custom roles
        var RoleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
        string[] roleNames = { "Admin", "Member", "Outcast" };
        IdentityResult roleResult;

        foreach (var roleName in roleNames)
        {
            //creating the roles and seeding them to the database
            var roleExist = await RoleManager.RoleExistsAsync(roleName);
            if (!roleExist)
            {
                roleResult = await RoleManager.CreateAsync(new IdentityRole(roleName));
            }
        }
}

Теперь этот код выдал исключение:

System.InvalidOperationException: 'Невозможно найти необходимые службы. Добавьте все необходимые службы, вызвав IServiceCollection.AddAuthorizationPolicyEvaluator внутри вызова ConfigureServices (...) в коде запуска приложения.

Добавление AddAuthorizationPolicyEvaluator ничего не меняет.

Какие-нибудь советы?

1 Ответ

0 голосов
/ 22 апреля 2019

Хорошо, я просто заставляю свое приложение работать должным образом :) Я думаю, что я просто отправлю сюда мой Startup.cs код для будущих вопросов - возможно, это кому-нибудь поможет.

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

        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
        services.AddDefaultIdentity<IdentityUser>(config =>
        {
            config.SignIn.RequireConfirmedEmail = true;
        })
            .AddRoles<IdentityRole>()
            .AddDefaultUI(UIFramework.Bootstrap4)
            .AddEntityFrameworkStores<ApplicationDbContext>();

        services.AddAuthorization(config =>
        {
            config.AddPolicy("RequireAdministratorRole",
                policy => policy.RequireRole("Administrator"));
            config.AddPolicy("RequireMemberRole",
                policy => policy.RequireRole("Member"));
        });

        services.AddTransient<IEmailSender, EmailSender>();
        services.Configure<AuthMessageSenderOptions>(Configuration);

        services.AddRazorPages()
            .AddNewtonsoftJson()
            .AddRazorPagesOptions(options => {
                options.Conventions.AuthorizePage("/Privacy", "RequireAdministratorRole");
            });
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider, UserManager<IdentityUser> userManager)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            // 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();

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages();
        });

        CreateDatabase(app);
        CreateRolesAsync(serviceProvider).Wait();
        CreateSuperUser(userManager).Wait();
    }

    private async Task CreateSuperUser(UserManager<IdentityUser> userManager)
    {
        var superUser = new IdentityUser { UserName = Configuration["SuperUserLogin"], Email = Configuration["SuperUserLogin"] };
        await userManager.CreateAsync(superUser, Configuration["SuperUserPassword"]);
        var token = await userManager.GenerateEmailConfirmationTokenAsync(superUser);
        await userManager.ConfirmEmailAsync(superUser, token);
        await userManager.AddToRoleAsync(superUser, "Admin");
    }

    private void CreateDatabase(IApplicationBuilder app)
    {
        using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
        {
            var context = serviceScope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
            context.Database.EnsureCreated();
        }
    }

    private async Task CreateRolesAsync(IServiceProvider serviceProvider)
    {
        //adding custom roles
        var RoleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
        string[] roleNames = { "Admin", "Member", "Outcast" };
        IdentityResult roleResult;

        foreach (var roleName in roleNames)
        {
            //creating the roles and seeding them to the database
            var roleExist = await RoleManager.RoleExistsAsync(roleName);
            if (!roleExist)
            {
                roleResult = await RoleManager.CreateAsync(new IdentityRole(roleName));
            }
        }
    }
}

Обычно приложение при запуске просто создает новую базу данных, добавляет роли «Администратор», «Участник» и «Изгой», а в конце создает учетную запись superUser на основе секретных данных пользователя. Дополнительно в файле Register.cshtml.cs У меня есть строка, которая добавляет роль «Участник» по умолчанию для новых участников

    public async Task<IActionResult> OnPostAsync(string returnUrl = null)
    {
        returnUrl = returnUrl ?? Url.Content("~/");
        if (ModelState.IsValid)
        {
            var user = new IdentityUser { UserName = Input.Email, Email = Input.Email };
            var result = await _userManager.CreateAsync(user, Input.Password);
            if (result.Succeeded)
            {
                _logger.LogInformation("User created a new account with password.");



                await _userManager.AddToRoleAsync(user, "Member");



                var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
                var callbackUrl = Url.Page(
                    "/Account/ConfirmEmail",
                    pageHandler: null,
                    values: new { userId = user.Id, code = code },
                    protocol: Request.Scheme);

                await _emailSender.SendEmailAsync(Input.Email, "Confirm your email to get acces to Functionality Matrix pages",
                    $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");

                // Block autologin after registration
                //await _signInManager.SignInAsync(user, isPersistent: false);
                return Redirect("./ConfirmEmailInfo");
            }
            foreach (var error in result.Errors)
            {
                ModelState.AddModelError(string.Empty, error.Description);
            }
        }

        // If we got this far, something failed, redisplay form
        return Page();
    }
}
...