如何在 Blazor 中注入服务 (AuthenticationStateProvider) class

How to inject service (AuthenticationStateProvider) in Blazor class

我正在努力在 Blazor 服务器的 class 中注入服务 (AuthenticationStateProvider)。如果我在 razor 组件中这样做,它非常简单:

@inject AuthenticationStateProvider AuthenticationStateProvider

然后

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

    if (user.Identity.IsAuthenticated)
    {
       ClientMachineName = $"{user.Identity.Name}";
    }
    else
    {
       ClientMachineName = "Unknown";
    }
} 

但是我需要这样做,即在 class 而不是 razor 组件中检索经过身份验证的用户机器名称。

我试过例如:

[Inject]
AuthenticationStateProvider AuthenticationStateProvider { get; set; }

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

    if (user.Identity.IsAuthenticated)
    {
        ClientMachineName = $"{user.Identity.Name}";
    }
    else
    {
        ClientMachineName = "Unknown";
    }
}

但这似乎不起作用。

如有任何帮助,我们将不胜感激。

使用 Blazor 服务器 (.Net Core 3),这对我有用:

public class AuthTest
{
    private readonly AuthenticationStateProvider _authenticationStateProvider;

    public AuthTest(AuthenticationStateProvider authenticationStateProvider)
    {
        _authenticationStateProvider = authenticationStateProvider;
    }

    public async Task<IIdentity> GetIdentity()
    {
        var authState = await _authenticationStateProvider.GetAuthenticationStateAsync();
        var user = authState.User;
        return user.Identity;
    }
}

您需要在 Startup.ConfigureServices 中的 ASP.Net 核心 DI 中注册它:

services.AddScoped<AuthTest>();

然后将其注入您的 .razor 页面:

@page "/AuthTest"
@inject AuthTest authTest;
<button @onclick="@LogUsername">Write user info to console</button>

@code{
    private async Task LogUsername()
    {
        var identity= await authTest.IsAuthenticated();
        Console.WriteLine(identity.Name);
    }

您应该会看到登录的用户名已写入 ASP.Net 输出控制台。

更新 如果您想从一个单独的 class 中获取当前登录的用户,并且您没有将其注入 blazor 页面,请按照指南 here

在这里查看我对这个问题的解决方案:

这应该可以解决您的问题。

编辑:如果您想获取有关身份验证状态的信息,您应该做的是使用用户名或您需要的任何详细信息在身份验证状态上创建声明,而不是创建 class 并为其分配名称。这样,在需要此信息的 classes 中,您只需注入一个服务 class 即可获取当前身份验证状态的所有声明。这真的应该全部在自定义身份验证状态提供程序中完成。

示例:

public override async Task<AuthenticationState> GetAuthenticationStateAsync()
{
    MyUser = //DB call to get user information
    var claimsIdentity = new ClaimsIdentity(new[] { new 
    Claim(ClaimTypes.Name, MyUser.Name) }, "Authenticated");
    var user = new ClaimsPrincipal(identity);
    return new AuthenticationState(user);
}

然后在另一个服务中,您将获得包含用户信息的声明,并将其注入到任何其他 service/class 需要的信息中。

public ApplicationUser(AuthenticationStateProvider authenticationStateProvider)
{
    _authenticationStateProvider = authenticationStateProvider;
}

public async Task<string> GetLogin()
{
    var authState = await _authenticationStateProvider.GetAuthenticationStateAsync();
    return authState.User.Claims.Where(c => c.Type == ClaimTypes.Name).FirstOrDefault().Value;
}

再次感谢@StephenByrne 和@Dan - 我现在几乎可以满足我的要求了。这是我的用户服务 class,它按预期工作:

public class AuthUser
{

    private readonly AuthenticationStateProvider _authenticationStateProvider;

    public AuthUser(AuthenticationStateProvider authenticationStateProvider)
    {
        _authenticationStateProvider = authenticationStateProvider;
        var username = _authenticationStateProvider.GetAuthenticationStateAsync().Result;
        FetchMyUser(username.User.Identity.Name);
    }

    public User MyUser { get; set; }

    public void FetchMyUser(string machineName = "Unknown")
    {
        using (IDbConnection connection = new System.Data.SqlClient.SqlConnection(SettingsService.DBConnectionString2016))
        {
            MyUser = connection.QueryFirstOrDefault<User>($"SELECT FirstName FROM MyTable WHERE MachineName = '{machineName}' ;");
        }
    }
}

然后在 Startup.cs 中我将此服务添加为 Scoped(这很重要,正如 Dan 在下面指出的);

services.AddScoped<AuthUser>();

然后我可以通过 .razor 组件使用此服务,如下所示:

@inject AuthUser authUser

Hello @authUser.MyUser.FirstName

我唯一剩下的问题是我不知道如何在另一个 .cs 中使用此服务 class。我相信我不应该简单地创建一个 class 的对象(我需要向其传递 authenticationStateProvider 参数)——这没有多大意义。知道如何实现与我在 .razor 文件中提到的相同但在 .cs class 中吗?

谢谢!

如果您在 startup.cs 添加一些服务

services.AddScoped<TokenProvider>();
services.AddTransient<TokenRefreshService>();
services.Add<GraphServiceService>();

您可以在 razor 页面中按类型注入它们

@inject TokenProvider _token
@inject TokenRefreshService _tokenrefresh
@inject GraphServiceService _graphservice

这些服务类,你通过构造函数注入它们

public GraphServiceClass(AuthenticationStateProvider _AuthenticationStateProvider, TokenProvider _token)
{
    AuthenticationStateProvider = _AuthenticationStateProvider;
    token = _token;
}

我推荐这个:ASP.NET Core Blazor dependency injection