如何在 blazor 页面上使用用户管理器?

问题描述

hello community 我有一个问题,如何在 usermanager 页面 webassembly 中使用 blazor?通过注入:

@inject UserManager<ApplicationUser> UserManager;

我得到的指示是缺少使用指令,因为 ApplicationUser 类位于服务器上,而客户端无权访问服务器。

这是我在 blazor 页面中的代码

@page "/index"
@inject AuthenticationStateProvider AuthenticationStateProvider
@using Microsoft.AspNetCore.Identity;
@inject UserManager<ApplicationUser> UserManager;

<button @onclick="@LogUsername">Write user info to console</button>
<br />
<br />
@Message

@code {
    string Message = "";

    private async Task LogUsername()
    {
        var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
        var user = authState.User;

        if (user.Identity.IsAuthenticated)
        {
            var currentUser = await UserManager.GetUserAsync(user);
            Message = ($"{user.Identity.Name} is authenticated.{ currentUser.Nombre }");
        }
        else
        {
            Message = ("The user is NOT authenticated.");
        }
    }
}

这是我的类 ApplicationUser:

    public class ApplicationUser: IdentityUser
        {
            public string Nombre { get; set; }
            public string ApellidoPaterno { get; set; }
            public string ApellidoMaterno { get; set; }
            public virtual Cliente InquilinoActual { get; set; }
        }

Image of an SQL Query

解决方法

您不能使用 WebAssembly Blazor 应用中的 UserManager,因为它在浏览器上运行。一般来说,您不能在 WebAssembly Blazor 应用程序中使用与数据库访问相关的对象。相反,您通常会创建一个 Web Api 操作方法,并使用 Fetch API (HttpClient) 访问这些方法。

您想从 User 对象中提取什么值?

什么是Nombre

无论 Nombre 是什么,您都可以将此值 (Nombre) 添加为声明并从 authState.User 访问它

更新

首先,您应该创建一个名为 ApplicationUserClaimsPrincipalFactory 的服务类,该类用于将表列的值从 Users 表转换为添加到传递给 Blazor 客户端的 ClaimsPrincipal 对象的声明。

(服务器应用程序)ApplicationUserClaimsPrincipalFactory.cs

using AuthenticationStateProviderCustomClaims.Server.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;


public class ApplicationUserClaimsPrincipalFactory : 
                       UserClaimsPrincipalFactory<ApplicationUser>
    {
        public ApplicationUserClaimsPrincipalFactory(UserManager<ApplicationUser> userManager,IOptions<IdentityOptions> optionsAccessor) : base(userManager,optionsAccessor)
        {
        }

        protected override async Task<ClaimsIdentity> 
                 GenerateClaimsAsync(ApplicationUser user)
        {
            ClaimsIdentity claims = await 
                            base.GenerateClaimsAsync(user);

            
            claims.AddClaim(new Claim("name",user.Nombre));
            
            return claims;
        }
        
    }

Startup.ConfigureServices

将以下内容放在 .AddDBContext 下方:

services.AddScoped<ApplicationUserClaimsPrincipalFactory>();

            services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
                .AddRoles<IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddClaimsPrincipalFactory<ApplicationUserClaimsPrincipalFactory>();

services.AddIdentityServer() .AddApiAuthorization(选项 => {

  // Note: This settings may be superfluous as the name claim 
  // is added by default.              
  options.IdentityResources["openid"].UserClaims.Add("name"); 
  options.ApiResources.Single().UserClaims.Add("name");  

          });

  services.AddAuthentication().AddIdentityServerJwt();

客户端

运行此代码,看看它是否有效...如果没有,请发布完整的错误报告

Index.razor

@page "/"

@using System.Security.Claims
@using Microsoft.AspNetCore.Components.Authorization
@inject AuthenticationStateProvider AuthenticationStateProvider

<p>@_authMessage</p>

@if (_claims != null && _claims.Count() > 0)
{
    <ul>
        @foreach (var claim in _claims)
        {
            <li>@claim.Type: @claim.Value</li>
        }
    </ul>
}

<p>@_nombreMessage</p>


@code {
    private string _authMessage;
    private string _nombreMessage;
    private IEnumerable<Claim> _claims = Enumerable.Empty<Claim>();

    private async Task GetClaimsPrincipalData()
    {
        var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
        var user = authState.User;

        if (user.Identity.IsAuthenticated)
        {
            _authMessage = $"{user.Identity.Name} is authenticated.";
            _claims = user.Claims;
            _nombreMessage =
            $"Nombre: {user.FindFirst(c => c.Type == ClaimTypes.Name)?.Value}";
        }
        else
        {
            _authMessage = "The user is NOT authenticated.";
        }
    }
    protected override async Task OnInitializedAsync()
    {
        await GetClaimsPrincipalData();
    }
}