Blazor HyBrid 授权讲解

2023-07-31,,

Blazor HyBrid 授权讲解

本文介绍 ASP.NET Core 对 Blazor Hybrid 应用中的安全配置和管理及 ASP.NET Core Identity 的支持。

Blazor Hybrid 应用中的身份验证由本机平台库处理,因为后者提供了浏览器沙盒无法给予的经过增强的安全保证。 本机应用的身份验证使用特定于操作系统的机制或通过联合协议,如 OpenID Connect (OIDC)。 按照针对应用选择的标识提供者指南进行操作,然后使用本文中的指南进一步集成标识与 Blazor。

集成身份验证必须为 Razor 组件和服务实现以下目标:

使用 Microsoft.AspNetCore.Components.Authorization 包中的抽象,例如 AuthorizeView。
对身份验证上下文中的更改做出回应。
访问凭据由标识提供者的应用预配,例如用于执行授权 API 调用的访问令牌。

准备工作

安装Masa Blazor的模板,如果已经安装则忽略

dotnet new install Masa.Template::1.0.0-rc.2

创建项目Photino项目模板

添加Microsoft.AspNetCore.Components.Authorization NuGet包到项目文件中

<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="7.0.5" />

自定义AuthenticationStateProvider处理程序

创建CustomAuthenticationStateProvider然后继承AuthenticationStateProvider

CustomAuthenticationStateProvider.cs代码文件

using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims; namespace MasaBlazorApp1; public class CustomAuthenticationStateProvider : AuthenticationStateProvider
{
private ClaimsPrincipal User { get; set; } public override Task<AuthenticationState> GetAuthenticationStateAsync()
{
if (User != null)
{
return Task.FromResult(new AuthenticationState(User));
}
var identity = new ClaimsIdentity();
User = new ClaimsPrincipal(identity); return Task.FromResult(new AuthenticationState(User));
} public void AuthenticateUser(string emailAddress)
{
var identity = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, emailAddress),
}, "Custom Authentication"); User = new ClaimsPrincipal(identity); NotifyAuthenticationStateChanged(
Task.FromResult(new AuthenticationState(User)));
}
}

在继承AuthenticationStateProvider方法会要重写GetAuthenticationStateAsync方法,用于给授权组件获取授权信息,

在这个代码当中的User是用于存储持久化我们的用户信息的如果需要对于授权修改,我们只需要修改这个自定义的处理程序即可。然后我们在CustomAuthenticationStateProvider中还自定义了AuthenticateUser这个是根据实际需求去实现,在目前这个代码中我们实现了个简单的Name在最后有一个NotifyAuthenticationStateChanged的调用,NotifyAuthenticationStateChanged是干啥的?NotifyAuthenticationStateChanged也是AuthenticationStateProvider提供的方法,核心功能是用于通知我们的授权状态被修改。

打开Program.cs然后注入我们的CustomAuthenticationStateProvider服务,在添加注入CustomAuthenticationStateProvider之前我们实现添加注入了AddAuthorizationCore,这个需要注意。

using MasaBlazorApp1;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Photino.Blazor; internal class Program
{
[STAThread]
private static void Main(string[] args)
{
var builder = PhotinoBlazorAppBuilder.CreateDefault(args); builder.RootComponents.Add<App>("#app");
builder.Services.AddMasaBlazor(); builder.Services.AddAuthorizationCore();
builder.Services.TryAddSingleton<AuthenticationStateProvider, CustomAuthenticationStateProvider>(); var app = builder.Build(); app.MainWindow
.SetTitle("Photino Blazor Sample"); AppDomain.CurrentDomain.UnhandledException += (sender, error) =>
{
}; app.Run();
}
}

然后继续打开我们的App.razor添加授权相关组件,修改之前在_Imports.razor添加以下引用

@using Microsoft.AspNetCore.Components.Authorization

添加未授权时显示的组件Shared/Login.razor,组件提供了一个输入框和一个按钮,输入框输入用户名,按钮则使用我们自定义的CustomAuthenticationStateProvider中提供的AuthenticateUser方法,用于更新授权信息从而刷新到授权的组件当中。

@inject AuthenticationStateProvider AuthenticationStateProvider

<MTextField @bind-Value="_userName" />

<MButton @onclick="SignIn">登录</MButton>

@code {
private string _userName = "账号"; private void SignIn()
{
((CustomAuthenticationStateProvider)AuthenticationStateProvider)
.AuthenticateUser(_userName);
}
}

App.razor文件

@namespace MasaBlazorApp1

<CascadingAuthenticationState>
<Router AppAssembly="@typeof(App).Assembly">
<Found Context="routeData">
<AuthorizeView>
<Authorized>
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
</RouteView>
</Authorized>
<NotAuthorized>
<Login/>
</NotAuthorized>
</AuthorizeView>
<FocusOnNavigate RouteData="@routeData" Selector="h1"/>
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState>

App.razor文件在Router中添加了AuthorizeView组件,用于显示授权显示的组件和未授权显示的组件。当有授权的情况下我们将使用默认的MainLayout布局,如果是未授权我们将实现Login,需要注意的是我们在组件最外层添加了CascadingAuthenticationState这个是核心组件,

CascadingAuthenticationState.cs 的反编译以后的代码,在组件当中注入了AuthenticationStateProvider然后在进入OnInitialized事件的时候对于AuthenticationStateProvider提供的AuthenticationStateChanged事件进行了监听,这个也就对应到了上面提到的NotifyAuthenticationStateChanged,当调用到NotifyAuthenticationStateChanged的时候会触发到AuthenticationStateChanged的事件,然后会触发组件的OnAuthenticationStateChanged方法,进行授权状态更新,这个也就是核心的组件。

    #line hidden
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
public partial class CascadingAuthenticationState : global::Microsoft.AspNetCore.Components.ComponentBase, IDisposable
{
#pragma warning disable 1998
protected override void BuildRenderTree(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
{
__builder.OpenComponent<global::Microsoft.AspNetCore.Components.CascadingValue<System.Threading.Tasks.Task<AuthenticationState>>>(0);
__builder.AddAttribute(1, "Value", global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck<System.Threading.Tasks.Task<AuthenticationState>>(
#nullable restore
#line 4 "D:\a\_work\1\s\src\Components\Authorization\src\CascadingAuthenticationState.razor"
_currentAuthenticationStateTask #line default
#line hidden
#nullable disable
));
__builder.AddAttribute(2, "ChildContent", (global::Microsoft.AspNetCore.Components.RenderFragment)(
#nullable restore
#line 4 "D:\a\_work\1\s\src\Components\Authorization\src\CascadingAuthenticationState.razor"
ChildContent #line default
#line hidden
#nullable disable
));
__builder.CloseComponent();
}
#pragma warning restore 1998
#nullable restore
#line 6 "D:\a\_work\1\s\src\Components\Authorization\src\CascadingAuthenticationState.razor" private Task<AuthenticationState>? _currentAuthenticationStateTask; /// <summary>
/// The content to which the authentication state should be provided.
/// </summary>
[Parameter]
public RenderFragment? ChildContent { get; set; } protected override void OnInitialized()
{
AuthenticationStateProvider.AuthenticationStateChanged += OnAuthenticationStateChanged; _currentAuthenticationStateTask = AuthenticationStateProvider
.GetAuthenticationStateAsync();
} private void OnAuthenticationStateChanged(Task<AuthenticationState> newAuthStateTask)
{
_ = InvokeAsync(() =>
{
_currentAuthenticationStateTask = newAuthStateTask;
StateHasChanged();
});
} void IDisposable.Dispose()
{
AuthenticationStateProvider.AuthenticationStateChanged -= OnAuthenticationStateChanged;
} #line default
#line hidden
#nullable disable
[global::Microsoft.AspNetCore.Components.InjectAttribute] private AuthenticationStateProvider AuthenticationStateProvider { get; set; }
}
}

效果

启动项目查看具体效果

默认进入登录界面,由于我们并没有授权信息,所以进入这个界面,然后我们随便输入一些内容点击登录。

当我们点击了登录按钮以后我们就进入到了MainLayout当中并且进入了首页。

对于授权Blazor由于模式都有所差异。

授权文档:ASP.NET Core Blazor Hybrid 身份验证和授权

结尾

来着token的分享

Blazor交流群:452761192

Blazor HyBrid 授权讲解的相关教程结束。

《Blazor HyBrid 授权讲解.doc》

下载本文的Word格式文档,以方便收藏与打印。