Custom AuthenticationStateProvider возвращает «пустой пользователь» - PullRequest
0 голосов
/ 04 мая 2020

в нашем приложении я бы хотел использовать управление пользователями нашего толстого клиента. Для этого я написал собственный 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, которое приводит к правильному вызову метода GetAuthenticationStateAsyn c. Теперь вошедший в систему пользователь правильно обернут внутри AuthenticationState. При отладке кода я вижу, что Identity with name name является правильным пользователем, а свойство IsAuthenticated имеет значение true.

Однако при использовании компонента AuthorizeView я всегда получаю «пустого пользователя» ( без имени, без имени пользователя, IsAuthenticated имеет значение false)

Теперь у меня есть небольшой компонент только для тестирования:

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

Я использую AuthorizeRouteView и CascadingAuthenticationState в App.razor, как в официальном примере, отображаемом в https://docs.microsoft.com/en-us/aspnet/core/security/blazor/?view=aspnetcore-3.1

Доступ к AuthenticationState через CascadingParameter также приводит к тому же «пустому пользователю».

Оценить любая помощь,

tilt32

EDIT 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, которую мы используем в фоновом режиме, требует зарегистрированного пользователя. Следовательно, я сделал гостя с ограниченными правами для решения этой проблемы. Таким образом, приложение входит в GetAuthenticationStateAsyn c и пытается запустить AuthenticationStateEvent непосредственно после запуска (во время экрана загрузки).

EDIT 2

Итак, я попробовал некоторые дополнительные этапы установки, из которых Microsoft написала в документации 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, IWebHostEnvironment env) я добавил следующие вызовы:

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

Это также не имело никакого эффекта.

1 Ответ

1 голос
/ 04 мая 2020

Я думаю, что объект AuthenticationState недоступен, потому что событие AuthenticationStateChanged не вызывается из AuthenticationStateProvider, и, таким образом, ваш AuthorizeView и ваши компоненты CascadingAuthenticationState не знают об изменении состояния. Проверьте свою логику c еще раз в этом направлении. Также убедитесь, что вы правильно добавили подклассный провайдер в контейнер DI. Я склонен полагать, что проблема в этом. Пожалуйста, покажите весь соответствующий код из метода ConfigureServices.

Обновление: Пожалуйста, попробуйте это:

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

Надеюсь, это поможет ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...