在 Blazor WebAssembly 应用程序中授权普通 Razor 页面?

Authorise normal Razor Pages in a Blazor WebAssemby App?

我正在使用 Blazor Wasm 编写 SPA。我使用了标准模板并包含了托管在服务器中的用户帐户,该服务器也创建了一个服务器应用程序。到目前为止一切都很好。 我要补充一点,我正在使用 .Net5 RC2,但我认为这不是我的问题。

我想在服务器和客户端应用程序中有一些 'normal' razor 页面。用户帐户身份服务器创建了文件夹结构 /Areas/Identity/Pages/.... 我添加了 /Areas/Management/Pages/Admin/Test.cshtml 和 Test.cshtml.cs 这些是非常简单的测试文件...

编辑 - 我编辑了这个以反映@enet 提出的问题。

剃须刀文件:

        @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 中:如果 [Authorize] 被删除,页面将加载,但将始终显示用户未获得授权。所以页面正在呈现,简单的测试产生 'else' 案例.. 在情况 B 中:页面根本不会呈现。 (此页面无效!- 来自浏览器的消息)。所以,根据我的研究,在这个: Razor Pages Authorization Conventions

我把我的 startup.cs 改成了:

           services.AddRazorPages();

对此:

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

        });

*** 我把上面的都去掉了,然后重置成原来的样子***

当我这样做时,结果与案例 B 相同,无论 .cs 文件中有无 [Authorize]。当您阅读文档时,我想这是有道理的。

所以我想我需要传回某种形式的授权令牌,或者?

身份页面不需要任何授权,因此这不是问题。 我的配置服务如下所示:

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

我觉得我在启动时缺少一些选项,任何想法..

我有答案,我想...

正在更改 Startup.cs 文件,其中我们有:

        services.AddAuthentication();

我改成了:

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

这将允许服务器提供带有身份验证的 razor 页面。

它还有另一个副作用,即改变服务器端对声明的感知方式,并导致任何 API 控制器能够以更传统的控制器方式工作。我会解释。我还有一个 'ApplicationUserController' 和一个 api 端点 'AddUpdateUser',它按照锡罐上的说明进行操作。

我有这个代码来检查登录用户:

       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。所以我不得不求助于使用以下代码从声明中查找用户 ID:

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

我也不得不搜索如何执行此操作。当然是在这个很棒的网站上找到的。

但是将这两行添加到启动,破坏了这段代码并使原始代码工作。我想我现在明白为什么了,人们说这一切都很好 'read the documentation' 但有时它太过分了。

无论如何,我希望这对一些人有所帮助。