【问题标题】:Custom AuthenticationStateProvider returns "empty user"自定义 AuthenticationStateProvider 返回“空用户”
【发布时间】:2020-08-18 16:00:21
【问题描述】:

在我们的应用程序中,我想使用胖客户端的用户管理。为此,我编写了一个自定义 AuthenticationStateProvider:

public class MyAuthenticationStateProvider : ServerAuthenticationStateProvider, IAuthentorizationService, IDisposable
{
    public MyAuthenticationStateProvider (IPermissionManager permissionManager)
    {
         //User management service of the fat client
        _permissionManager = permissionManager;
    }

    public override Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        if (_permissionManager.PermissionUser == null)
        {
            var emptyUser = new ClaimsPrincipal(new ClaimsIdentity(new Claim[0]));
            return Task.FromResult(new AuthenticationState(emptyUser));
        }
        var identity = new ClaimsIdentity(new[]
        {
            new Claim(ClaimTypes.Name, _permissionManager.PermissionUser.User.GetName())
        }, "FatClientAuthentication");
        var user = new ClaimsPrincipal(identity);
        return Task.FromResult(new AuthenticationState(user));
    }

    public async Task<bool> LoginUser(string userName, string password)
    {
        //Login via WCF connection
        var response = await _clientProxy.Login(new LoginRequest
        {
            LoginUserName = userName,
            Password = password

        });
        response.LogExceptionIfFaulted(_logger);
        if (response.Ok)
        {
            _permissionManager.Initialize(response.LoggedInUser);
            NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
        }
        return response.Ok;
    }

登录工作正常。出于测试目的,我总是使用固定的用户凭据登录。成功登录后,我触发 NotifyAuthenticationStateChanged 事件,这会导致正确调用 GetAuthenticationStateAsync 方法。现在登录的用户被正确地包装在 AuthenticationState 中。在调试代码时,我可以看到带有名称声明的 Identity 是正确的用户,并且 IsAuthenticated 属性为 true。

但是,当使用“AuthorizeView”组件时,我总是得到一个“空用户”(没有名称声明,没有用户名,IsAuthenticated 为假)

我现在有一个小组件仅用于测试:

<AuthorizeView>
<Authorized>
    <h2>User @context.User.Identity.Name</h2> is logged in!
    Claims:
    <ul>
        @foreach (var claim in context.User.Claims)
        {
            <li>Type=@claim.Type; Value=@claim.Value</li>
        }
    </ul>
    @context.User.Claims
    <p>Current count: @currentCount</p>

    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
</Authorized>
<NotAuthorized>
    <h2>User @context.User.Identity.Name</h2> @*this is an empty string*@
    <h2>Authentication Type: @context.User.Identity.AuthenticationType</h2> @*empty*@
    <h2>Authenticated: @context.User.Identity.IsAuthenticated</h2>@*false*@
    No user is logged in!
</NotAuthorized>

我在 App.razor 中使用 AuthorizeRouteView 和 CascadingAuthenticationState 就像在https://docs.microsoft.com/en-us/aspnet/core/security/blazor/?view=aspnetcore-3.1中显示的官方示例中一样

通过 CascadingParameter 访问 AuthenticationState 也会导致相同的“空用户”。

感谢任何帮助,

tilt32

编辑 1

所以我再次查看了登录行为,确保调用了该事件。 然后我发现,我的 AuthenticationStateChanged 事件没有订阅者(为空)。我的印象是,框架中的某些内容在启动时附加到此事件。也许我在启动时忘记了一些配置方法调用?这就是我在配置服务中所做的:

    services.AddScoped<AuthenticationStateProvider, MyAuthenticationStateProvider>();
            services.AddScoped<ServerAuthenticationStateProvider, MyAuthenticationStateProvider>();
//Interface which I use in my LoginCompontent and at Startup to log in with the default user or some real user credentials
            services.AddScoped<IAuthenticationService, MyAuthenticationStateProvider>();

我还尝试了用户 enet 建议的方法。可悲的是没有成功,结果是一样的。在登录期间,调用 NotifyAuthenticationStateChanged 并因此调用没有订阅者的事件。

我们在后台使用的 WCF 服务需要登录用户。因此,我创建了一个具有有限权限的来宾用户来解决这个问题。因此,应用程序进入 GetAuthenticationStateAsync 并尝试在启动后直接触发 AuthenticationStateEvent(在加载屏幕期间)。

编辑 2

所以我现在尝试了一些额外的设置步骤,微软在 Blazor 文档中写道,它们对于服务器端 blazor 来说不是必需的:

ConfigureServices 现在看起来像这样

//Authentication & Authorization setup
services.AddOptions();
services.AddAuthenticationCore();
services.AddAuthorizationCore();
services.AddScoped<IPermissionManager, SingleUserPermissionManager>();
services.AddScoped<AuthenticationStateProvider, MyAuthenticationStateProvider>();
services.AddScoped<ServerAuthenticationStateProvider, MyAuthenticationStateProvider>();
services.AddScoped<IAuthenticationService, MyAuthenticationStateProvider>();

在 Configure(IApplicationBuilder app, IWebHostEnvironment env) 方法中,我添加了以下调用:

app.UseAuthentication();
app.UseAuthorization();

这也没有任何效果。

【问题讨论】:

    标签: authentication server-side blazor


    【解决方案1】:

    我认为 AuthenticationState 对象不可用,因为 AuthenticationStateChanged 事件不是从 AuthenticationStateProvider 调用的,因此您的 AuthorizeView 和 CascadingAuthenticationState 组件不知道状态更改。在这个方向上再次检查你的逻辑。还要确保将子类提供程序正确添加到 DI 容器。我倾向于认为问题在于这个。请显示 ConfigureServices 方法中的所有相关代码。

    更新: 请试试这个:

    services.AddScoped<MyAuthenticationStateProvider>();
    services.AddScoped<AuthenticationStateProvider>(provider => 
      provider.GetRequiredService<MyAuthenticationStateProvider>());
    

    希望对你有帮助……

    【讨论】:

    • 您好,感谢您的回复。关于 ConfigureServices 方法中的授权和身份验证,我唯一要做的就是调用 services.AddScoped()。根据我从 Microsoft 文档中了解到的情况,这应该足够了吗?
    • 感谢您的回复。我更新了问题。不知何故,我的 AuthenticationStateChangedevent 为空
    猜你喜欢
    • 1970-01-01
    • 2023-03-25
    • 2022-01-05
    • 2020-10-29
    • 1970-01-01
    • 1970-01-01
    • 2014-01-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多