Авторизовать обычные страницы Razor в приложении Blazor WebAssemby?

#c# #razor #authorization #blazor

#c# #razor #авторизация #blazor

Вопрос:

Я пишу SPA с использованием Blazor Wasm. Я использовал стандартный шаблон и включил учетные записи пользователей, размещенные на сервере, который также создал серверное приложение. Пока все в порядке. Я бы добавил, что я использую.Net5 RC2 но я не думаю, что это моя проблема здесь.

Я хочу иметь несколько «обычных» страниц razor на сервере, а также в клиентском приложении. Сервер идентификации учетных записей пользователей создал структуру папок / Areas/Identity/Pages/…. Я добавил /Areas/Management/Pages/Admin/Test.cshtml и Test.cshtml.cs Это очень простые тестовые файлы…

РЕДАКТИРОВАТЬ — я отредактировал это, чтобы отразить вопросы, заданные @enet.

Файл razor:

         @page
        @model ProjName.Server.Areas.Management.Pages.Admin.TestModel

        <h1>Test Page</h1>

    @if (User.Identity.IsAuthenticated)
    {
        @if (User.IsInRole("Administrator"))
        {
            <h2>User is Admin</h2>
        }
        else
        {
            <h2>User is not an admin</h2>
        }
    }
    else
    {
        <h2>User is Not Authenticated</h2>
    }

        @{
        }
  

Файл .CS:

         namespace ProjName.Server.Areas.Management.Pages.Admin
        {
            [Authorize]    <<<--- See case B.
            public class TestModel : PageModel
            {
                public void OnGet()
                {
                }
            }
        }
  

Я хочу, чтобы на странице было указано, что либо пользователь является администратором, либо пользователь не является администратором.
В случае A: если [Авторизовать] удалено, страница загрузится, но всегда будет показывать, что пользователь не авторизован. Итак, страница визуализируется, и простой тест выдает случай «else»..
В случае B: страница вообще не будет отображаться. (Эта страница не работает! — сообщение от браузера). Итак, из моих исследований в этом:
Соглашения об авторизации страниц Razor

Я изменил свой startup.cs с этого:

            services.AddRazorPages();
  

к этому:

             services.AddRazorPages(options =>
        {
            options.Conventions.AuthorizeAreaFolder("Management", "/Admin");

        });
  

*** Я удалил вышеупомянутое и сбросил его до того, как это было ***

Когда я это делаю, получается тот же результат, что и в случае B, с или без [Авторизовать] в файле .cs. Я думаю, это имеет смысл, когда вы читаете документы.

Так что, я думаю, мне нужно вернуть какую-то форму токена авторизации обратно или?

Страницы идентификации не требуют никакой авторизации, поэтому это не проблема. Мои службы настройки выглядят так:

             public void ConfigureServices(IServiceCollection services)
            {
                services.AddDbContext<RGDbContext>(options =>
                    options.UseSqlServer(
                        Configuration.GetConnectionString("DefaultConnection")));

                services.AddDatabaseDeveloperPageExceptionFilter();

                services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
                    .AddRoles<IdentityRole>()
                    .AddEntityFrameworkStores<RGDbContext>();

                // This was put in to try to sort this https://github.com/dotnet/AspNetCore.Docs/issues/17517
                //services.Configure<IdentityOptions>(options =>
                //    options.ClaimsIdentity.UserIdClaimType = ClaimTypes.NameIdentifier);

                services.AddIdentityServer()
                    .AddApiAuthorization<ApplicationUser, RGDbContext>(options => {
                        options.IdentityResources["openid"].UserClaims.Add("name");
                        options.ApiResources.Single().UserClaims.Add("name");
                        options.IdentityResources["openid"].UserClaims.Add("role");
                        options.ApiResources.Single().UserClaims.Add("role");
                    });

                services.AddAuthentication()
                    .AddIdentityServerJwt();



                services.AddControllersWithViews();
                //services.AddRazorPages();
                services.AddRazorPages(options =>
                {
                    options.Conventions.AuthorizeAreaFolder("Management", "/Admin");

                });
                

                .... more of my own stuff...
  

*** Переход на страницу сервера осуществляется с кнопки в NavMenu, вызывающей событие onclick для этого:

     private void ServerPageTest()
    {
        Navigation.NavigateTo("/Management/Admin/Test", true);
    }
  

У меня такое чувство, что мне не хватает некоторых опций в моем запуске, есть мысли..

Ответ №1:

Я думаю, у меня есть ответ…

Изменение файла Startup.cs, где у нас есть:

         services.AddAuthentication();
  

Я изменил его на:

         services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
            options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
        })
  

Затем это позволяет серверу обслуживать страницы razor с аутентификацией.

Это также имело еще один побочный эффект, заключающийся в изменении того, как утверждения воспринимаются обратно на сервере, и приводит к тому, что любые контроллеры API могут работать более традиционным способом контроллера. Я объясню. У меня также есть «ApplicationUserController» с конечной точкой API «AddUpdateUser», которая делает то, что написано на tin.

У меня был этот код для проверки зарегистрированного пользователя:

        public async Task<ActionResult<ApplicationUserDTO>> AddUpdateUser(ApplicationUserDTO sentUser)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }
        // Get the logged in user.
        // This line should work but doesnt and I dont know why.
        ApplicationUser loggedinUserX = await _userManager.GetUserAsync(User).ConfigureAwait(false);
  

Но он всегда возвращал null. и поэтому мне пришлось прибегнуть к поиску идентификатора пользователя из утверждений с помощью этого кода:

         string loggedinUserId = User.FindFirstValue(ClaimTypes.NameIdentifier);
        ApplicationUser loggedinUser = _context.Users.Find(loggedinUserId);
  

Мне также пришлось искать, как это сделать. Конечно, нашел это на этом замечательном сайте.

Но добавление двух строк при запуске нарушило этот код и заставило исходный код работать. Думаю, теперь я понимаю, почему, и людям очень хорошо говорить «прочитайте документацию», но иногда это просто слишком сложно.

В любом случае, я надеюсь, что это поможет некоторым людям.