在 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' 但有时它太过分了。
无论如何,我希望这对一些人有所帮助。
我正在使用 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' 但有时它太过分了。
无论如何,我希望这对一些人有所帮助。