我们已经有一个正在运行的 Blazor WebAssembly 应用程序(ASP.NET Core 托管),并根据 本教程 实现了身份验证/授权。我们在项目中添加了角色,以限制用户只能访问某些内容。
后端使用 Microsoft.AspNetCore.Identity 作为 NuGet 依赖项。
我们希望为此项目实现一个 .NET MAUI 应用程序,该应用程序应该为用户使用相同的数据库,因此无需再次注册。
我们仍然希望为 Blazor 应用程序使用相同的后端,因此解决方案必须是与 Blazor 和 .NET MAUI 兼容。
.NET MAUI 有没有办法使用与 Microsoft.AspNetCore.Identity 创建的相同用户/角色?如果可能的话,我们如何根据用户的角色渲染 UI 元素?
@philipp8230,抱歉这么久才回复您。实际上,我一直在致力于一个项目,试图让 NTLM/Negotiate 在 .Net Maui 上工作,并决定使用带有个人帐户的身份来使用 .Net 8 来重新设计我们的服务器端。有一些新的简洁的 .8 功能允许Identity APIs。
我将现有的 .7 服务器端转换为 .8 Blazor Web App/Web Assembly,包括带有 SQL 个人帐户的身份以及对 ApplicationUser:IdentityUser 的自定义。我还有一些用于管理用户和角色的自定义组件页面。
接下来,我通过更改 Program.cs 中的这一行来公开现有的 Identity API 端点:
builder.Services.AddIdentityCore<ApplicationUser>(options =>
options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddSignInManager();
到
builder.Services.AddIdentityApiEndpoints<ApplicationUser> (options =>
options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddSignInManager();
//For Swagger
builder.Services.AddEndpointsApiExplorer();
...
app.MapIdentityApi<ApplicationUser>();
在 Maui 客户端上,我选择使用“身份 Api 端点提供的令牌”来使用服务器端的 Api。对于我想在服务器端和毛伊岛共享的页面,我转移到带有页面和视图的 Razor 类库。这些页面通过具有 Authorize 属性的服务器端 Api 处理数据。我为 HttpClient 创建了一个共享服务,用于管理登录(初始令牌)、刷新令牌等。使用个人身份凭证获取令牌的代码示例:
private async Task Login()
{
if (BearerToken == null)
{
try
{
var loginResponse = await client.PostAsJsonAsync("/login", new { email = UserName, password = Password });
if (loginResponse.IsSuccessStatusCode) {
BearerToken = await loginResponse.Content.ReadFromJsonAsync<ClientToken>();
BearerToken.expiresOn = DateTime.Now.AddSeconds(BearerToken.expiresIn - 1800);
client.DefaultRequestHeaders.Authorization = new("Bearer", BearerToken.accessToken);
}
else
{
BearerToken = null;
}
}
catch(Exception ex)
{
BearerToken = null;
}
}
else
{
try
{
if (BearerToken.expiresOn > DateTime.Now)
{
var loginResponse = await client.PostAsJsonAsync("/refresh", new { refreshToken = BearerToken.refreshToken });
if (loginResponse.IsSuccessStatusCode)
{
BearerToken = await loginResponse.Content.ReadFromJsonAsync<ClientToken>();
BearerToken.expiresOn = DateTime.Now.AddSeconds(BearerToken.expiresIn - 1800);
client.DefaultRequestHeaders.Authorization = new("Bearer", BearerToken.accessToken);
}
else { BearerToken = null; }
}
}
catch(Exception ex)
{
BearerToken = null;
}
}
return;
}
我在应用程序端点的基本 Get、Put、Post 等之前调用了 login()。如果现有令牌存在,则 login() 将返回,否则刷新或通过 Identity Api 端点再次登录。
在 Maui 客户端上,我将 HttpClient 服务添加为单例以维护令牌:
builder.Services.AddSingleton<HttpService>();
我还添加了一个 Login.razor 页面,并在 HttpService 中添加了一个公共登录(字符串用户名,字符串秘密)以从用户获取初始令牌。
到目前为止一切顺利,我已经获得了相同的用户列表、角色、授权等。顺便说一句,我还添加了新的 .Net 8 Identity Razor 组件页面,以用后面的 .cshtml 代码替换旧的 razor 页面服务器端:
// Add additional endpoints required by the Identity /Account Razor components.
app.MapAdditionalIdentityEndpoints();