asp.netコアで現在のユーザーを取得する方法


128

メールなどのユーザーの情報を取得して、現在のユーザーを取得したい。しかし、asp.netコアではそれができません。私はとても混乱していますこれは私のコードです

HttpContextコントローラのコンストラクタではほとんどnull です。各アクションでユーザーを獲得することは良くありません。ユーザーの情報を一度取得してViewData、に設定したい。

public DashboardController()
{
    var user = HttpContext.User.GetUserId();
}

5
MVCまたはWeb APiで使用しますか?
Tushar

回答:


172
User.FindFirst(ClaimTypes.NameIdentifier).Value

コンストラクタの編集

以下のコードは機能します:

public Controller(IHttpContextAccessor httpContextAccessor)
{
    var userId = httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value 
}

RTM用に編集

登録する必要がありますIHttpContextAccessor

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHttpContextAccessor();
    }

2
アクションで動作しますが、コントローラのコンストラクタで使用したいです。
Mehran Hafizi 16

3
クラスでこれを使用することは可能ですか?
Mehran Hafizi 16

5
ClaimTypes.NameIdentifier現在のユーザーIDとClaimTypes.Nameユーザー名を提供します。
Nikolay Kostov

3
誰かがUserPrincipal.Current.Nameの何が問題になっているのか教えてもらえますか?
ティプラ

2
@ademcaglin何らかの理由でユーザーがnull私の場合に戻ってきますか?私は使用して.Net core 2.1 Web apiいます。
Sruthi Varghese

54

動作する簡単な方法と私はチェックしました。

private readonly UserManager<IdentityUser> _userManager;
public CompetitionsController(UserManager<IdentityUser> userManager)
{
    _userManager = userManager;
}

var user = await _userManager.GetUserAsync(HttpContext.User);

次に、この変数のすべてのプロパティをのようにできuser.Emailます。これが誰かの役に立つことを願っています。

編集

これは一見単純なことですが、ASP.NET Coreのさまざまな種類の認証システムの複雑な原因です。一部の人が入手してnullいる原因を更新します。

JWT認証の場合(ASP.NET Core v3.0.0-preview7でテスト済み):

var email = HttpContext.User.Claims.FirstOrDefault(c => c.Type == "sub")?.Value;

var user = await _userManager.FindByEmailAsync(email);

1
asp.net Core 2.0のコントローラー内で私にとってはうまく機能します
jmdon

2
_userManagerとは
NullVoxPopuli

6
ASP.NET Core Identityでは、ユーザーマネージャーはDependency Inject to Create Usersによって提供されるサービスです。参照ドキュメント:詳細は
アフマド

2
非同期でない方法でこれをどのように達成できますか?
T3.0

私にとってはnullを返します。どうして?
AlbertoCláudioMandlate

22

Asp.NET Coreで現在のユーザーを取得する別の方法があります-そして私はそれをここのどこかで見たと思います^^

// Stores UserManager
private readonly UserManager<ApplicationUser> _manager; 

// Inject UserManager using dependency injection.
// Works only if you choose "Individual user accounts" during project creation.
public DemoController(UserManager<ApplicationUser> manager)  
{  
    _manager = manager;  
}

// You can also just take part after return and use it in async methods.
private async Task<ApplicationUser> GetCurrentUser()  
{  
    return await _manager.GetUserAsync(HttpContext.User);  
}  

// Generic demo method.
public async Task DemoMethod()  
{  
    var user = await GetCurrentUser(); 
    string userEmail = user.Email; // Here you gets user email 
    string userId = user.Id;
}  

そのコードは、DemoControllerという名前のコントローラーに送られます。両方が待たないと動作しません(コンパイルされません);)


これにはIDの使用が必要です
Fraze

1
ApplicationUserとは何ですか?
Mike

これ等の追加の特性で拡張できるようにApplicationUserは、典型的IdentityUserから継承されている
Corgalore

20

コンストラクター内でHttpContextがnullであることにかなり驚いたと言わざるを得ません。パフォーマンス上の理由からだと思います。IPrincipal以下で説明するように使用すると、コンストラクタに注入されることが確認されています。基本的には、受け入れられた回答と同じですが、よりインターフェイス的な方法で行われます。


この質問を見つけて、一般的な「現在のユーザーを取得するにはどうすればよいですか?」Userから直接アクセスできますController.User。しかし、これはアクションメソッドの内部でのみ実行できます(コントローラーはHttpContextsでのみ実行されないため、またパフォーマンス上の理由によります)。

ただし、(OPが行ったように)コンストラクターでそれを必要とする場合、または現在のユーザーを必要とする他の注入可能なオブジェクトを作成する必要がある場合は、以下がより良いアプローチです。

IPrincipalを注入してユーザーを取得する

最初に会っIPrincipalIIdentity

public interface IPrincipal
{
    IIdentity Identity { get; }
    bool IsInRole(string role);
}

public interface IIdentity
{
    string AuthenticationType { get; }
    bool IsAuthenticated { get; }
    string Name { get; }
}

IPrincipalIIdentityユーザーとユーザー名を表します。「プリンシパル」が奇妙に聞こえる場合、ウィキペディアはあなたを慰めるでしょう

かどうかをあなたからそれを得ることを認識することが重要IHttpContextAccessor.HttpContext.UserControllerBase.UserまたはControllerBase.HttpContext.Userあなたがしていますことが保証されているオブジェクトになっClaimsPrincipalている実装するオブジェクトをIPrincipal

User現在、ASP.NETが使用する他の種類のユーザーはありません(ただし、他の何かが実装できなかったと言っているわけではありませんIPrincipal)。

だからあなたが注入したい「現在のユーザー名」の依存関係を持つものがある場合は、注入する必要があります IPrincipalありIHttpContextAccessorます。

重要:IPrincipalコントローラーまたはアクションメソッドに直接注入する時間を無駄にしないでくださいUser。既に利用できるので、それは無意味です。

startup.cs

   // Inject IPrincipal
   services.AddTransient<IPrincipal>(provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);

次に、注入するユーザーを必要とするDIオブジェクトで IPrincipal、現在のユーザーを取得するためにする。

ここで最も重要なことは、ユニットテストを実行している場合、を送信する必要はなくHttpContextただ表すことができるものを模擬する必要があるだけですIPrincipal ClaimsPrincipal

100%よくわからない、もう1つ重要なこと。実際の申し立てにアクセスする必要がある場合は、ClaimsPrincipalにキャストIPrincipalする必要がありますClaimsPrincipal。実行時にそれがそのタイプであることを100%知っているので、これは問題ありません(それがそうであるためHttpContext.User)。私は実際にこれをコンストラクタで実行するのが好きですIPrincipal になりますClaimsPrincipal

モックする場合はClaimsPrincipal直接作成しますをそれを任意のテイクに渡しますIPrincipal

なぜインターフェースがないのか正確にはわかりIClaimsPrincipalません。私はMSがClaimsPrincipalインターフェースを保証しない特別な「コレクション」であると決定したと思います。


2
これにより、現在のユーザーをアプリケーションの任意の場所に挿入できます。
マチャド

1
これは機能しません。私はいつもnull注射を受けIPrincipalます。それ以外の場合はクラッシュするため(GetServiceがnullを返す)、一時サービスを…GetService<IHttpContextAccessor>()?.HttpContext.User…(を使用して?)追加する必要もありました。
ygoe

services.AddTransient(provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);HttpContext.UserがClaimsPrincipalであるのと同じようにできます。
Jay Zelos

18

現在(2017年4月)現在、次のように機能しているようです。

public string LoggedInUser => User.Identity.Name;

少なくとも中に Controller


4
タイプ 'System.Security.Principal.IIdentity'を暗黙的に 'string'に変換することはできません。
アンソニー・ファン、

3
string LoggedInUser = User.Identity.Name;
Alic W

5
この=>演算子の使用をこれまでに見たことのない人のために、「式本体の定義」と呼ばれ、このドキュメントで説明されています。私のような将来の人々が疑問に思っている場合に備えて。
ネイサンクレメント

上のコメントにも記載されているように、からIIdentityへの変換がない場合、コードは編集前にコンパイルできなかった可能性がありますstring。編集は単にそれを修正しました。どのようにして結論に達したかはわかりません(特に、「editor」ポイントは2kの評判を下回るユーザーにのみ付与されるため)。
fuglede

9

おそらく私は答えを見なかったかもしれませんが、これが私のやり方です。

  1. .Net Core->プロパティ-> launchSettings.json

これらの値を変更する必要があります

"windowsAuthentication": true, // needs to be true
"anonymousAuthentication": false,  // needs to be false 

Startup.cs-> ConfigureServices(...)

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

MVCまたはWeb APIコントローラー

private readonly IHttpContextAccessor _httpContextAccessor;
//constructor then
_httpContextAccessor = httpContextAccessor;

コントローラー方式:

string userName = _httpContextAccessor.HttpContext.User.Identity.Name;

結果はuserNameです。例= Domain \ username


4

私の問題は、cshtmlファイルのオブジェクトとして、ログインしたユーザーにアクセスすることでした。ViewDataでユーザーが必要であることを考えると、このアプローチが役立つ場合があります。

cshtmlファイル

@using Microsoft.AspNetCore.Identity
@inject UserManager<ApplicationUser> UserManager

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>
    @UserManager.FindByNameAsync(UserManager.GetUserName(User)).Result.Email
    </title>
  </head>
  <body>

  </body>
</html>

ロードするナビゲーションプロパティを取得する方法(ApplicationUserクラスの会社のナビゲーションプロパティの会社名)。ナビゲーションプロパティを含める方法が見つかりませんでした。
ハンターネルソン、

1

既存の回答に加えて、ユーザー関連のデータUserIDなどを保持するクラスインスタンスをアプリ全体で利用できるようにすることもできます。

たとえばリファクタリング に役立つ場合がありますUserIDすべてのコントローラーアクションでフェッチしUserID、サービスレイヤーに関連するすべてのメソッドで追加のパラメーターを宣言する必要はありません。

私は調査を行いました、そしてこれが私の投稿です。

プロパティDbContextを追加してUserId(またはカスタムを実装して)派生したクラスを拡張するだけです。Sessionこのプロパティを持つクラスを。

フィルターレベルでは、クラスインスタンスをフェッチしてUserId値を設定できます。

その後、インスタンスを挿入する場所に-必要なデータが含まれます(ライフタイムはリクエストごとでなければならないため、AddScopedメソッドを使用して登録します)。

作業例:

public class AppInitializationFilter : IAsyncActionFilter
{
    private DBContextWithUserAuditing _dbContext;

    public AppInitializationFilter(
        DBContextWithUserAuditing dbContext
        )
    {
        _dbContext = dbContext;
    }

    public async Task OnActionExecutionAsync(
        ActionExecutingContext context,
        ActionExecutionDelegate next
        )
    {
        string userId = null;
        int? tenantId = null;

        var claimsIdentity = (ClaimsIdentity)context.HttpContext.User.Identity;

        var userIdClaim = claimsIdentity.Claims.SingleOrDefault(c => c.Type == ClaimTypes.NameIdentifier);
        if (userIdClaim != null)
        {
            userId = userIdClaim.Value;
        }

        var tenantIdClaim = claimsIdentity.Claims.SingleOrDefault(c => c.Type == CustomClaims.TenantId);
        if (tenantIdClaim != null)
        {
            tenantId = !string.IsNullOrEmpty(tenantIdClaim.Value) ? int.Parse(tenantIdClaim.Value) : (int?)null;
        }

        _dbContext.UserId = userId;
        _dbContext.TenantId = tenantId;

        var resultContext = await next();
    }
}

詳細については、私の回答を参照しください。


0

撮影IdentityUserもうまくいきます。これは現在のユーザーオブジェクトであり、ユーザーのすべての値を取得できます。

private readonly UserManager<IdentityUser> _userManager;
public yourController(UserManager<IdentityUser> userManager)
{
    _userManager = userManager;
}

var user = await _userManager.GetUserAsync(HttpContext.User);

0

scafolded Identityを使用し、Asp.net Core 2.2+を使用している場合は、次のようなビューから現在のユーザーにアクセスできます。

@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager

 @if (SignInManager.IsSignedIn(User))
    {
        <p>Hello @User.Identity.Name!</p>
    }
    else
    {
        <p>You're not signed in!</p>
    }

https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity?view=aspnetcore-2.2&tabs=visual-studio


0

これは古い質問ですが、私のケースは私のケースがここで議論されなかったことを示しています。

私はSimon_Weaver(https://stackoverflow.com/a/54411397/2903893)の答えが一番好きです。彼はIPrincipalとIIdentityを使用してユーザー名を取得する方法を詳しく説明しています。この答えは完全に正しいので、このアプローチを使用することをお勧めします。ただし、デバッグ中に、ASP.NETがサービスプリンシパルを適切に設定できないという問題が発生しました。(つまり、IPrincipal.Identity.Nameはnullです)

ユーザー名を取得するには、MVCフレームワークがどこかから取得する必要があることは明らかです。.NETの世界では、ASP.NETまたはASP.NET CoreはOpen ID Connectミドルウェアを使用しています。単純なシナリオでは、WebアプリはWebブラウザーでユーザーを認証します。このシナリオでは、WebアプリケーションはユーザーのブラウザーにユーザーをAzure ADにサインインするように指示します。Azure ADは、ユーザーのブラウザーを介してサインインレスポンスを返します。これには、ユーザーに関するクレームがセキュリティトークンに含まれています。これをアプリケーションのコードで機能させるには、Webアプリのサインインを委任する権限を提供する必要があります。AzureサービスにWebアプリを展開する場合、この要件を満たすための一般的なシナリオは、Webアプリを構成することです: "App Services"-> YourApp-> "Authentication / Authorization"ブレード-> "App Service Authenticatio" = "On"https://github.com/Huachao/azure-content/blob/master/articles/app-service-api/app-service-api-authentication.md)。私は、このプロセスのフードの下で、ウィザードが次の段落で示すものと同じ設定を追加することにより、このWebアプリの「親」Web構成を調整すると信じています(これは私の推測です)。基本的に、このアプローチがASP.NET Coreで機能しないのは、「親」のマシン構成がwebconfigによって無視されるためです。(これは100%確実ではありません。私が持っている最良の説明をします)。したがって、それを機能させるには、アプリでこれを手動で設定する必要があります。

ここでは、Azure ADを使用するようにアプリを頻繁にセットアップする方法を説明する記事を示します。 https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/aspnetcore2-2

手順1:サンプルをAzure ADテナントに登録します。(当然のことですが、説明に時間をかけたくないです)。

ステップ2:appsettings.jsonファイルで、ClientID値を、ステップ1のアプリケーション登録ポータルで登録したアプリケーションのアプリケーションIDに置き換えます。TenantId値を一般的な

手順3:Startup.csファイルを開き、ConfigureServicesメソッドで、.AddAzureADを含む行に次のコードを挿入します。これにより、アプリケーションはAzure AD v2.0エンドポイントを使用してユーザーをサインインできます。 Microsoft個人アカウント。

services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
    options.Authority = options.Authority + "/v2.0/";
    options.TokenValidationParameters.ValidateIssuer = false;
});

要約:トピックスターターが説明されているというエラーにつながる可能性のあるもう1つの問題を示しました。この問題の理由は、Azure AD(Open IDミドルウェア)の構成がないためです。この問題を解決するために、私は手動で「認証/承認」を設定することを提案します。これを設定する方法の短い概要が追加されます。


0

答えのほとんどは、HttpContextドキュメントから最も適切に処理する方法を示しています。これは私が行ったものでもあります。

デバッグ時にプロジェクト設定を確認することをお勧めしますEnable Anonymous Authentication = true。デフォルトはです。


-1

私は私の解決策を得ました

var claim = HttpContext.User.CurrentUserID();

public static class XYZ
{
    public static int CurrentUserID(this ClaimsPrincipal claim)
    {
        var userID = claimsPrincipal.Claims.ToList().Find(r => r.Type == 
         "UserID").Value;
        return Convert.ToInt32(userID);
    }
    public static string CurrentUserRole(this ClaimsPrincipal claim)
    {
        var role = claimsPrincipal.Claims.ToList().Find(r => r.Type == 
        "Role").Value;
        return role;
    }
}

1
このコードは質問に答えることがありますが、問題を解決する方法理由に関する追加のコンテキストを提供すると、回答の長期的な価値が向上します。
アレクサンダー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.