我正在努力使 Blazor 中的身份验证/授权与一些公共页面(如登录、隐私政策、错误页面等)结合使用。经过多次修补后,它似乎有效,但我无法想象我所做的方式是推荐的方式。我正在使用 Auth0 进行身份验证——我不确定这是否重要(可能不重要)。
我正在将 Blazor 服务器 Web 应用程序与 .Net 8 结合使用,该应用程序是从 .Net 7 Blazor 服务器应用程序转换而来。
我不会发布整个 Routes.razor,但它引用了 MainLayout (我认为这是标准的):
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
MainLayout.razor 然后有一个带有几层身份验证的 AuthorizedView。 @Body 嵌套在 Authorized 部分内的 ErrorBoundary 中,第二个 @Body 标记位于 NotAuthorized 部分(下面仅是部分片段):
<AuthorizeView>
<Authorized>
[...]
<ErrorBoundary @ref="_errorBoundary">
<ChildContent>
@Body
</ChildContent>
<ErrorContent Context="ex">
@{
OnError(ex);
}
<p>Something has gone wrong. The error has been logged.</p>
</ErrorContent>
</ErrorBoundary>
[...]
</Authorized>
<NotAuthorized>
@Body
</NotAuthorized>
</AuthorizeView>
背后的代码 (MainLayout.razor.cs) 在 Init 上执行以下操作:
private static readonly List<string> PublicUris = new() { "/privacy", "/login", "/error" };
protected override async Task OnInitializedAsync()
{
var authenticationStateAsync = await AuthStateProvider.GetAuthenticationStateAsync();
User = authenticationStateAsync.User;
var baseUri = NavigationManager.BaseUri.TrimEnd('/');
//TODO: is this how it needs to work?
//Note: all public pages would have to be added to this page?
var publicPage = PublicUris.Select(p => baseUri + p).Contains(NavigationManager.Uri);
if (User.Identity is not { IsAuthenticated: true } && !publicPage)
{
NavigationManager.NavigateTo($"/{UnauthorizedRedirectUrl}");
}
await base.OnInitializedAsync();
}
这有点笨拙,但要点是如果当前页面不是公共页面并且用户未登录,则重定向到登录页面。
Program.cs 的一些内容。不确定有多少相关:
builder.Services
.AddAuth0WebAppAuthentication(options => {[...]
//added based on: https://stackoverflow.com/questions/74555220/custom-loginpath-no-effect-in-asp-net-mvc-with-auth0
builder.Services.Configure<CookieAuthenticationOptions>(CookieAuthenticationDefaults.AuthenticationScheme, options => {
options.LoginPath = "/";
options.LogoutPath = "/Identity/Logout";
});
[...]
builder.Services.AddAuthorization(options =>
{[policies that I don't think are relevant]...
[...]
app.UseAuthentication();
app.UseAuthorization();
再次,这似乎可以工作,无论是否登录都可以看到公共页面,并且不需要需要AllowAnonymous属性才能看到。
也就是说,我还没有在任何地方找到一篇文章建议这样做,或者说任何有关检查主布局页面后面的代码中的当前 Uri 和重定向的内容。
如何在 Blazor 应用程序中同时支持安全页面和公共页面,而无需进行类似上述的设计?
您可以将
@attribute [Authorize]
添加到 _Imports.razor
以使授权全局化。然后将 @attribute [AllowAnonymous]
添加到公共页面。@attribute [Authorize]
,然后添加自定义授权处理程序以根据请求 Uri 确定身份验证结果。 public class MyAuthHandler : IAuthorizationHandler
{
private readonly IHttpContextAccessor accessor;
private static readonly List<string> PublicUris = new() { "/counter", "/login", "/error" };
public MyAuthHandler(IHttpContextAccessor accessor)
{
this.accessor = accessor;
}
public Task HandleAsync(AuthorizationHandlerContext context)
{
var currentUri = accessor.HttpContext.Request.Path;
var pendingRequirements = context.PendingRequirements.ToList();
foreach (var requirement in pendingRequirements)
{
if (PublicUris.Contains(currentUri))
{
context.Succeed(requirement);
}
}
return Task.CompletedTask;
}
}
然后在程序.cs中
builder.Services.AddHttpContextAccessor();
builder.Services.AddSingleton<IAuthorizationHandler, MyAuthHandler>();
builder.Services.AddAuthorization(...);
请注意,所有注册的“IAuthorizationHandler”都将由默认授权服务进行处理。 https://learn.microsoft.com/en-us/aspnet/core/security/authorization/policies?view=aspnetcore-8.0#iauthorizationservice