web-dev-qa-db-ja.com

Blazorコンポーネントで現在のユーザーを取得する

BlazorとWindows認証で新しいサイトを開始し、ページ/コンポーネントを表示している現在のユーザーを特定する必要があります。

Razorページの場合、現在のユーザー名にはContext.User.Identity.Nameを使用してアクセスできますが、これはBlazorコンポーネントでは機能しないようです。コンポーネントにHttpContextを挿入しようとしましたが、実行時にコンテキストがnullです。

おまけとして、これを最終的にStartup.csに組み込みたいので、ユーザー名を1回取得するだけで済み、アプリケーションで企業ユーザークラス(EF Coreを使用)を利用できます。そのユースケースに合わせた回答もいただければ幸いです。

4
Wes H

これで、コンポーネントだけでなく、一般的なクラスでも機能するようになりました。

HttpContextユーザーにアクセスするには、 ConfigureServices、Startup.csに追加

_services.AddHttpContextAccessor();
_

CorporateUserクラスにCorporateUserServiceクラスがあります。サービスクラスは、コンストラクターインジェクションを通じてDbContextを取得します。

次に、CorporateUserServiceを継承する新しいCurrentCorporateUserServiceを作成しました。コンストラクター注入を通じて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();
}
_
1
Wes H

更新-この回答は機能しません。削除するのではなく、情報としてここに示します。代わりに、質問に対する他の回答を検討してください。

  1. ConfigureServicesのStartup.csにservices.AddHttpContextAccessor();を追加します
  2. コンポーネントクラス[注:null型を有効にして分離コードを使用します]
_        [Inject]
        private IHttpContextAccessor HttpContextAccessor { get; set; } = default!;

        private string username = default!;
_
  1. コンポーネントコード(コードビハインド)のprotected override void OnInitialized()
_        username = HttpContextAccessor.HttpContext.User.Identity.Name;
_

usernameは、他の変数と同じようにコンポーネント全体で使用できるようになりました。

ただし、この質問の他の回答を参照して、任意のクラスで使用できるサービスから現在のユーザー名を取得してください。

1
Wes H

これは私が動くターゲットを追いかけるのにつらい旅でした。私の場合、Razorページで使用されるBlazorコンポーネントのユーザー名のみが必要でした。私の解決策は以下を必要としました:

Index.cshtml.csに2つのプロパティとコンストラクタを追加しました

    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.cshtmlで、次のように呼び出したコンポーネントを追加します。

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

私のコンポーネントでは、コードビハインドファイル(パブリッククラスFileMainBase:ComponentBaseを使用するFileMain.razor.cs)を使用しています。コードは次のとおりです。

    [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>
0
azpc

参考までに、同様の要件があり、以下を使用しています。

var authstate = await AuthenticationsStateProvider.GetAuthenticationStateAsync();
var user = authstate.User;
var name = user.Identity.Name;

私はすでに、startup.csにAuthenticationsStateProviderがあり、それをカスタムクラスのコンストラクターに追加しました。

0
DarrenB