Получить текущего пользователя в компоненте Blazor - PullRequest
2 голосов
/ 17 февраля 2020

Я начинаю новый сайт с Blazor и Windows Аутентификация и мне нужно идентифицировать текущего пользователя, просматривающего страницу / компонент.

Для страницы Razor, текущее имя пользователя можно получить с помощью Context.User.Identity.Name, но это не работает в компоненте Blazor. Я пытался внедрить HttpContext в компонент, но Context не имеет значения во время выполнения.

В качестве бонуса, я в конечном итоге захочу включить это в Startup.cs, поэтому мне нужно только один раз получить имя пользователя и использовать его. класс корпоративных пользователей (с EF Core) для моих приложений. Ответы, адаптированные к этому варианту использования, также приветствуются.

Ответы [ 4 ]

3 голосов
/ 17 февраля 2020

Вот как у меня это работает в компоненте:

  1. В ConfigureServices, в Startup.cs, добавьте services.AddHttpContextAccessor();
  2. в свой класс компонентов [Примечание: я использую выделение кода с включенными нулевыми типами]
        [Inject]
        private IHttpContextAccessor HttpContextAccessor { get; set; } = default!;

        private string username = default!;
В вашем коде компонента (код позади), в protected override void OnInitialized()
        username = HttpContextAccessor.HttpContext.User.Identity.Name;

username теперь можно использовать по всему компоненту, как и любую другую переменную.

Тем не менее, см. Мой другой ответ в этом вопросе, чтобы добавить получение текущего имени пользователя из службы, используемой в любом классе.

1 голос
/ 17 февраля 2020

Существует три возможности получить пользователя в компоненте (страница является компонентом):

  1. Внедрить IHttpContextAccessor и получить из него доступ HttpContext, а затем User
  2. Введите свойство AuthenticationStateProvider, вызовите GetAuthenticationStateAsync и получите от него User
  3. Оберните ваш компонент в <CascadingAuthenticationState> компонент, объявите свойство Task<AuthenticationState> и вызовите его, чтобы получить User (аналогично # 2)

Подробнее здесь: https://docs.microsoft.com/en-us/aspnet/core/security/blazor.

0 голосов
/ 24 февраля 2020

Теперь я могу заставить его работать с общим классом, а также с компонентом.

Чтобы получить доступ к пользователю HttpContext; в ConfigureServices в Startup.cs добавьте

services.AddHttpContextAccessor();

У меня есть класс CorporateUserService для моего класса CorporateUser. Класс обслуживания получает DbContext посредством внедрения конструктора.

Затем я создал новый CurrentCorporateUserService, который наследуется от CorporateUserService. Он принимает DbContext и IHttpContextAccessor через внедрение конструктора

public class CurrentCorporateUserService : CorporateUserService
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public CurrentCorporateUserService(IHttpContextAccessor httpContextAccessor, MyDbContext context) : base(context)
    {
        _httpContextAccessor = httpContextAccessor;
    }
    ...

Базовый класс обслуживания имеет метод GetUserByUsername(string username). Текущий класс обслуживания добавляет дополнительный метод

public CorporateUser GetCurrentUser()
{
    return base.GetUserByUsername(_httpContextAccessor.HttpContext.User.Identity.Name.Substring(8));
}

Текущий класс обслуживания зарегистрирован в Startup.cs

services.AddScoped<CurrentCorporateUserService>();

Как только это будет сделано, я могу использовать CurrentCorporateUserService в компоненте с внедрение директивы.

    [Inject]
    private CurrentCorporateUserService CurrentCorporateUserService { get; set; } = 
    default!;

или в любом классе, с инжекцией в конструктор.

    public MyDbContext( DbContextOptions<MyDbContext> options
                  , CurrentCorporateUserService CurrentCorporateUserService )
                  : base(options) 
    {
        _currentUser = CurrentCorporateUserService.GetCurrentUser();
    }

Создание сервиса для всего проекта означает, что все мои разработчики не должны заботиться о том, как получить Текущий пользователь, им просто нужно внедрить сервис в свой класс.

Например, использование его в MyDbContext делает текущего пользователя доступным для каждого события сохранения. В приведенном ниже коде любой класс, который наследует класс BaseReport, будет автоматически обновлять метаданные отчета при сохранении записи.

public override Int32 SaveChanges()
{         
    var entries = ChangeTracker.Entries().Where(e => e.Entity is BaseReport
    && (e.State == EntityState.Added || e.State == EntityState.Modified));

            foreach (var entityEntry in entries)
            {
                ((BaseReport)entityEntry.Entity).ModifiedDate = DateTime.Now;
                ((BaseReport)entityEntry.Entity).ModifiedByUser = _currentUser.Username;

            }

    return base.SaveChanges();
}
0 голосов
/ 22 февраля 2020

Это было болезненное путешествие для меня, преследующего движущуюся цель. В моем случае мне нужно было только имя пользователя для моего компонента Blazor, используемого на странице Razor. Моему решению требовалось следующее:

В Index.cs html .cs я добавил два свойства и конструктор

    public IHttpContextAccessor HttpContextAccessor { get; set; }
    public string UserName { get; set; }

    public TestModel(IHttpContextAccessor httpContextAccessor)
    {
        HttpContextAccessor = httpContextAccessor;
        if (HttpContextAccessor != null) UserName = HttpContextAccessor.HttpContext.User.Identity.Name;
    }

Затем в Index.cs html, где я добавил компонент, который я назвал следующим образом:

<component type="typeof(MyApp.Components.FileMain)" param-UserName="Model.UserName" render-mode="ServerPrerendered" />

В моем компоненте я использую код, стоящий за файлом (FileMain.razor.cs, используя publi c класс FileMainBase: ComponentBase), имеющий код:

    [Parameter]
    public string UserName { get; set; } = default!;

и затем в качестве подтверждения концепции я добавил на страницу FileMain.razor

    <div class="form-group-sm">
    <label class="control-label">User: </label>
    @if (UserName != null)
    {
        <span>@UserName</span>
    }
</div>
...