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

Posted

技术标签:

【中文标题】如何在 Blazor 类中注入服务(AuthenticationStateProvider)【英文标题】:How to inject service (AuthenticationStateProvider) in Blazor class 【发布时间】:2020-05-01 08:45:56 【问题描述】:

我正在努力在 Blazor 服务器的类中注入服务 (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";
    
 

但是我需要这样做,即在类而不是 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";
    

但这似乎不起作用。

任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

使用 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 Core 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 输出控制台。

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

【讨论】:

谢谢斯蒂芬 - 但我的问题是我想从另一个类使用这个“AuthTest”服务,而不是从 .razor 页面(你的最后一步)。本质上,我想在 .cs 文件中获取 identity.Name 输出(我的用户服务,我使用此用户名来检索有关用户的信息)。知道怎么做吗?谢谢 @PeterPirc - 哦,我明白了,我的错。好的,你能描述一下它是如何不起作用的吗? @StephenByrne 感谢您为我指明了正确的方向,但每当我这样做时,我的 httpContext 总是返回 null(我已经注册了该服务)。我不确定发生了什么……有什么建议吗?为澄清起见,我正在使用带有 Windows 身份验证的服务器端应用程序;我只想访问我的服务类中的声明(IE,经过身份验证的用户的登录名/电子邮件)。 @PeterPirc - 澄清一下,这段代码的入口点是什么,是 blazor 代码部分还是 WebApi 控制器? 您好@StephenByrne - 非常感谢您提供的帮助,非常感谢。我需要多玩一点;但是我相信 httpContextAccessor 检索服务器用户名而不是客户端用户名。我会进行更多调查并报告。此外,Dan 在下面提供的答案似乎可以解决我的问题。【参考方案2】:

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

Accessinging an authenticated user outside of a view in Blazor

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

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

例子:

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);

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

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;

【讨论】:

这可能是它!我无法在您的其他帖子中发表评论(声誉低:),但您能否让我知道它的语法是什么:“将 AuthenticationStateProvider 注入您的服务类” 没问题!基本上它是我在链接中的代码......在您尝试使用提供程序的类中,您需要为其创建一个以 AuthenticationStateProvider 作为参数的构造函数。然后,您将其分配给类中的只读 _authenticationStateProvider 并使用它来执行您的操作。这有意义吗?如果没有,请告诉我! 已编辑答案...应该这样做...我刚刚在我的应用程序中实现了相同的功能。【参考方案3】:

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

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 类中使用此服务。我相信我不应该简单地创建该类的对象(我需要向其传递 authenticationStateProvider 参数)——这没有多大意义。知道如何实现与我在 .razor 文件中提到的相同,而是在 .cs 类中吗?

谢谢!

【讨论】:

我在代码中很少使用authenticationStateProvider,我想在这个答案中使用_authenticationStateProvider.GetAuthenticationStateAsync().Result;。如果.Result 的使用最少,是否可以接受?【参考方案4】:

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

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

您可以在剃须刀页面中按类型注入它们

@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

【讨论】:

以上是关于如何在 Blazor 类中注入服务(AuthenticationStateProvider)的主要内容,如果未能解决你的问题,请参考以下文章

具有不可注入参数的服务和通用类的 Blazor 构造函数注入 [重复]

如何将服务注入 Blazor?

Blazor IStringLocalizer 向服务注入

在自定义类中访问 Blazor 服务器端的 AuthenticationStateProvider

如何将 Blazor 中的所有注册服务添加到 Simple Injector?

在 blazor 中使用自定义组件时在注入的差异服务中调用 HttpContextAccesor 后为 null